diff --git a/.gitignore b/.gitignore index 734b460..986cb2b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /priestessconfig.txt /priestessconfig.txtbkup /target/ +dependency-reduced-pom.xml diff --git a/src/main/java/com/tinyplantnews/priestess/Command.java b/src/main/java/com/tinyplantnews/priestess/Command.java index d2e7ed4..d763ae2 100644 --- a/src/main/java/com/tinyplantnews/priestess/Command.java +++ b/src/main/java/com/tinyplantnews/priestess/Command.java @@ -21,106 +21,107 @@ import reactor.core.publisher.Mono; * @author atomb */ public class Command { - - public static final HashMap commands = new HashMap<>(); - - private static final Logger log = Logger.getLogger(Priestess.class.getName()); - - public static void replyTo(Message m, String s){ - if(m != null){ - m.getChannel().block().createMessage(s).withMessageReference(m.getId()).block(); - } else { - log.log(Level.INFO, s); - } - } - static void tryAll(String commandline, Message m, int permissionLevel) { - for(String s: commands.keySet()){ - if(commandline.startsWith(s)){ - log.log(Level.INFO, "Matched command " + s); - switch(commands.get(s).tryExecuteCommand(commandline, permissionLevel, m)){ - case SUCCESS: - return; - case BADPERM: - replyTo(m, "Insufficient permissions for command."); - return; - case FAILURE: - replyTo(m, String.format("Command %s failed for some reason idfk", s)); - return; - } - } - } - replyTo(m, "Unknown command"); - } - - private final String name; - private final int namelen; - private final int permissionLevel; - private Callback callback; - - /** - * - * @param commandline - * @param permissionLevel - * @param a - * @return - */ - public CommandStatus tryExecuteCommand(String commandline, int permissionLevel, Message m){ - if(!commandline.startsWith(this.name)){ - return NOMATCH; - } - if(permissionLevel < this.permissionLevel){ - return BADPERM; - } - String payload = commandline.substring(this.namelen).trim(); - this.callback.apply(new CommandArgs(m, payload, permissionLevel)); - return SUCCESS; - } - - public Command setCallback(Callback c){ - this.callback = c; - return this; - } - - Command(String name, int permissionLevel){ - this.name = name; - this.namelen = name.length(); - this.permissionLevel = permissionLevel; - this.callback = new Callback(){ - @Override - public Publisher apply(CommandArgs t) { - t.replyWith(String.format("Callback for function %s not registered", name)); - return null; - } - - }; - } - - public static void registerCommand(Command c){ - commands.put(c.name, c); - } - - /*= "use emoji"; - public static final String REPLYTO_COMMAND = "reply to"; - public static final String SENDTO_COMMAND = "send to";*/ + public static final HashMap commands = new HashMap<>(); - /** - * @return the name - */ - public String getName() { - return name; - } - - public static Command commandThatJustRepliesWith(String name, String reply){ - Command c = new Command(name, 1); - c.setCallback(new Callback(){ + private static final Logger log = Logger.getLogger(Priestess.class.getName()); - @Override - public Publisher apply(CommandArgs t) { - t.replyWith(reply); - return Mono.empty(); - } - }); - return c; - } + public static void replyTo(Message m, String s) { + if (m != null) { + m.getChannel().block().createMessage(s).withMessageReference(m.getId()).block(); + } else { + log.log(Level.INFO, s); + } + } + + static void tryAll(String commandline, Message m, int permissionLevel) { + for (String s : commands.keySet()) { + if (commandline.startsWith(s)) { + log.log(Level.INFO, "Matched command " + s); + switch (commands.get(s).tryExecuteCommand(commandline, permissionLevel, m)) { + case SUCCESS: + return; + case BADPERM: + replyTo(m, "Insufficient permissions for command."); + return; + case FAILURE: + replyTo(m, String.format("Command %s failed for some reason idfk", s)); + return; + } + } + } + replyTo(m, "Unknown command"); + } + + private final String name; + private final int namelen; + private final int permissionLevel; + private Callback callback; + + /** + * + * @param commandline + * @param permissionLevel + * @param a + * @return + */ + public CommandStatus tryExecuteCommand(String commandline, int permissionLevel, Message m) { + if (!commandline.startsWith(this.name)) { + return NOMATCH; + } + if (permissionLevel < this.permissionLevel) { + return BADPERM; + } + String payload = commandline.substring(this.namelen).trim(); + this.callback.apply(new CommandArgs(m, payload, permissionLevel)); + return SUCCESS; + } + + public Command setCallback(Callback c) { + this.callback = c; + return this; + } + + Command(String name, int permissionLevel) { + this.name = name; + this.namelen = name.length(); + this.permissionLevel = permissionLevel; + this.callback = new Callback() { + @Override + public Publisher apply(CommandArgs t) { + t.replyWith(String.format("Callback for function %s not registered", name)); + return null; + } + + }; + } + + public static void registerCommand(Command c) { + commands.put(c.name, c); + } + + /* + * = "use emoji"; public static final String REPLYTO_COMMAND = "reply to"; + * public static final String SENDTO_COMMAND = "send to"; + */ + + /** + * @return the name + */ + public String getName() { + return name; + } + + public static Command commandThatJustRepliesWith(String name, String reply) { + Command c = new Command(name, 1); + c.setCallback(new Callback() { + + @Override + public Publisher apply(CommandArgs t) { + t.replyWith(reply); + return Mono.empty(); + } + }); + return c; + } } diff --git a/src/main/java/com/tinyplantnews/priestess/CommandArgs.java b/src/main/java/com/tinyplantnews/priestess/CommandArgs.java index e0bc7f3..fabe0fc 100644 --- a/src/main/java/com/tinyplantnews/priestess/CommandArgs.java +++ b/src/main/java/com/tinyplantnews/priestess/CommandArgs.java @@ -13,39 +13,39 @@ import discord4j.core.object.entity.channel.MessageChannel; */ public class CommandArgs { - private Message m; - private String payload; - private final int permCalledWith; + private Message m; + private String payload; + private final int permCalledWith; - public CommandArgs(Message m, String payload, int permCalledWith) { - this.m = m; - this.payload = payload; - this.permCalledWith = permCalledWith; - } + public CommandArgs(Message m, String payload, int permCalledWith) { + this.m = m; + this.payload = payload; + this.permCalledWith = permCalledWith; + } - /** - * @return the m - */ - public Message getMessage() { - return m; - } + /** + * @return the m + */ + public Message getMessage() { + return m; + } - /** - * @return the payload - */ - public String getPayload() { - return payload; - } - - public void replyWith(String s){ - Command.replyTo(m, s); - } + /** + * @return the payload + */ + public String getPayload() { + return payload; + } + + public void replyWith(String s) { + Command.replyTo(m, s); + } + + /** + * @return the permCalledWith + */ + public int getPermCalledWith() { + return permCalledWith; + } - /** - * @return the permCalledWith - */ - public int getPermCalledWith() { - return permCalledWith; - } - } diff --git a/src/main/java/com/tinyplantnews/priestess/CommandStatus.java b/src/main/java/com/tinyplantnews/priestess/CommandStatus.java index 41dc5b3..562009b 100644 --- a/src/main/java/com/tinyplantnews/priestess/CommandStatus.java +++ b/src/main/java/com/tinyplantnews/priestess/CommandStatus.java @@ -9,8 +9,5 @@ package com.tinyplantnews.priestess; * @author atomb */ public enum CommandStatus { - NOMATCH, - SUCCESS, - FAILURE, - BADPERM; + NOMATCH, SUCCESS, FAILURE, BADPERM; } diff --git a/src/main/java/com/tinyplantnews/priestess/Configuration.java b/src/main/java/com/tinyplantnews/priestess/Configuration.java index befe4cd..b72872f 100644 --- a/src/main/java/com/tinyplantnews/priestess/Configuration.java +++ b/src/main/java/com/tinyplantnews/priestess/Configuration.java @@ -30,171 +30,179 @@ import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; /** - * - * @author twi + * "Ms Merry," you may say, "You literally import the Preferences class, and yet + * you insist on writing your own configuration store. Why?" "Iunno," I reply. + * + * @author sandy */ public class Configuration { - private static String CONFIG_FILE_LOCATION = null; - public static final String CONFIG_FILE_KEY = "PRIESTESS_CONFIG"; - public static final Properties props = System.getProperties(); - public static final Preferences prefs = Preferences.userNodeForPackage(Configuration.class); - public static final String DEFAULT_CONFIG_FILE_NAME = "priestessconfig.txt"; + private static String CONFIG_FILE_LOCATION = null; + public static final String CONFIG_FILE_KEY = "PRIESTESS_CONFIG"; + public static final Properties props = System.getProperties(); + public static final Preferences prefs = Preferences.userNodeForPackage(Configuration.class); + public static final String DEFAULT_CONFIG_FILE_NAME = "priestessconfig.txt"; - private static HashMap configuration = new HashMap<>(); + private static HashMap configuration = new HashMap<>(); - private static final Logger log = Logger.getLogger(Configuration.class.getName()); + private static final Logger log = Logger.getLogger(Configuration.class.getName()); - public static String findConfigurationFilePath() { - if (getCONFIG_FILE_LOCATION() != null) { - return getCONFIG_FILE_LOCATION(); - } - setCONFIG_FILE_LOCATION(setConfigurationFilePath(), false); - return getCONFIG_FILE_LOCATION(); - } + public static String findConfigurationFilePath() { + if (getCONFIG_FILE_LOCATION() != null) { + return getCONFIG_FILE_LOCATION(); + } + setCONFIG_FILE_LOCATION(setConfigurationFilePath(), false); + return getCONFIG_FILE_LOCATION(); + } - private static String setConfigurationFilePath() { - String s = System.getenv(CONFIG_FILE_KEY); - if (s != null && !s.isBlank()) { - return s; - } else if (props.containsKey(CONFIG_FILE_KEY)) { - return props.getProperty(CONFIG_FILE_KEY); - } - s = prefs.get(CONFIG_FILE_KEY, ""); - if (s != null && !s.isBlank()) { - return s; - } - if (Files.exists(Paths.get(DEFAULT_CONFIG_FILE_NAME), LinkOption.NOFOLLOW_LINKS)) { - return DEFAULT_CONFIG_FILE_NAME; - } - //JDialog jd = new JDialog(); - //jd.add(new JLabel("Choose where to put Priestess Working Directory")); - //jd.setVisible(true); - JOptionPane.showConfirmDialog(null, "Select where cult files will be stored."); - JFileChooser jfc = new JFileChooser("Config File for Discord Cult Priestess"); - jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - int rv; - boolean approved = false; - while (!approved) { - rv = jfc.showDialog(null, "Select"); - if (rv == JFileChooser.APPROVE_OPTION) { - File f = jfc.getSelectedFile(); - if (f.isDirectory() && f.canRead() && f.canWrite()) { - prefs.put(CONFIG_FILE_KEY, f.getAbsolutePath()); - try { - prefs.flush(); - } catch (BackingStoreException e) { - log.log(Level.WARNING, "Backing store exception while committing configuration file path to persistent storage {0}", e.getMessage()); - } - return f.getAbsolutePath(); - } - } else if(rv == JFileChooser.CANCEL_OPTION) { - return ""; - } + private static String setConfigurationFilePath() { + String s = System.getenv(CONFIG_FILE_KEY); + if (s != null && !s.isBlank()) { + return s; + } else if (props.containsKey(CONFIG_FILE_KEY)) { + return props.getProperty(CONFIG_FILE_KEY); + } + s = prefs.get(CONFIG_FILE_KEY, ""); + if (s != null && !s.isBlank()) { + return s; + } + if (Files.exists(Paths.get(DEFAULT_CONFIG_FILE_NAME), LinkOption.NOFOLLOW_LINKS)) { + return DEFAULT_CONFIG_FILE_NAME; + } + // JDialog jd = new JDialog(); + // jd.add(new JLabel("Choose where to put Priestess Working Directory")); + // jd.setVisible(true); + JOptionPane.showConfirmDialog(null, "Select where cult files will be stored."); + JFileChooser jfc = new JFileChooser("Config File for Discord Cult Priestess"); + jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + int rv; + boolean approved = false; + while (!approved) { + rv = jfc.showDialog(null, "Select"); + if (rv == JFileChooser.APPROVE_OPTION) { + File f = jfc.getSelectedFile(); + if (f.isDirectory() && f.canRead() && f.canWrite()) { + return f.getAbsolutePath(); + } + } else if (rv == JFileChooser.CANCEL_OPTION) { + return ""; + } - } - return ""; - } + } + return ""; + } - private static final String delimiter = ": "; + private static final String delimiter = ": "; - public static void getConfigurationFromFile() { - if (CONFIG_FILE_LOCATION == null) { - setConfigurationFilePath(); - } - try { - if (Files.isDirectory(Paths.get(CONFIG_FILE_LOCATION), LinkOption.NOFOLLOW_LINKS)) { - CONFIG_FILE_LOCATION = CONFIG_FILE_LOCATION + System.getProperty("file.separator") + DEFAULT_CONFIG_FILE_NAME; - } - BufferedReader br = new BufferedReader(new FileReader(Paths.get(CONFIG_FILE_LOCATION).toFile())); - br.lines().forEach((s) -> { - String key = s.substring(0, s.indexOf(delimiter)); - if (s.length() == s.indexOf(delimiter) + delimiter.length()) { - System.out.println("read empty value for key (" + key + ") from configuration file"); - configuration.put(key, ""); - } else { - String value = s.substring(s.indexOf(delimiter) + delimiter.length()); - configuration.put(key, value); - } - }); - } catch (FileNotFoundException ex) { + public static void getConfigurationFromFile() { + if (CONFIG_FILE_LOCATION == null) { + setConfigurationFilePath(); + } + try { + if (Files.isDirectory(Paths.get(CONFIG_FILE_LOCATION), LinkOption.NOFOLLOW_LINKS)) { + CONFIG_FILE_LOCATION = CONFIG_FILE_LOCATION + System.getProperty("file.separator") + + DEFAULT_CONFIG_FILE_NAME; + } + BufferedReader br = new BufferedReader(new FileReader(Paths.get(CONFIG_FILE_LOCATION).toFile())); + br.lines().forEach((s) -> { + String key = s.substring(0, s.indexOf(delimiter)); + if (s.length() == s.indexOf(delimiter) + delimiter.length()) { + log.log(Level.FINE, "read empty value for key (" + key + ") from configuration file"); + configuration.put(key, ""); + } else { + String value = s.substring(s.indexOf(delimiter) + delimiter.length()); + configuration.put(key, value); + } + }); + } catch (FileNotFoundException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, "Error loading configuration file from (" + CONFIG_FILE_LOCATION + ") {0}", ex); - } - } + Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, + "Error loading configuration file from (" + CONFIG_FILE_LOCATION + ") {0}", ex); + } + } - /** - * @return the CONFIG_FILE_LOCATION - */ - public static String getCONFIG_FILE_LOCATION() { - return CONFIG_FILE_LOCATION; - } + /** + * @return the CONFIG_FILE_LOCATION + */ + public static String getCONFIG_FILE_LOCATION() { + return CONFIG_FILE_LOCATION; + } - /** - * @param aCONFIG_FILE_LOCATION the CONFIG_FILE_LOCATION to set - */ - public static void setCONFIG_FILE_LOCATION(String aCONFIG_FILE_LOCATION, boolean persistent) { - CONFIG_FILE_LOCATION = aCONFIG_FILE_LOCATION; - if (persistent) { - props.setProperty(CONFIG_FILE_KEY, CONFIG_FILE_LOCATION); - } + /** + * @param aCONFIG_FILE_LOCATION the CONFIG_FILE_LOCATION to set + */ + public static void setCONFIG_FILE_LOCATION(String aCONFIG_FILE_LOCATION, boolean persistent) { + CONFIG_FILE_LOCATION = aCONFIG_FILE_LOCATION; + if (persistent) { + props.setProperty(CONFIG_FILE_KEY, CONFIG_FILE_LOCATION); + prefs.put(CONFIG_FILE_KEY, CONFIG_FILE_LOCATION); + try { + prefs.flush(); + } catch (BackingStoreException e) { + log.log(Level.WARNING, + "Backing store exception while committing configuration file path to persistent storage {0}", + e.getMessage()); + } + } - } + } - public static void setConfigurationParameter(String key, String value) { - configuration.put(key, value); - } + public static void setConfigurationParameter(String key, String value) { + configuration.put(key, value); + } - public static String getConfigurationParameter(String key) { - if (configuration.containsKey(key)) { - return configuration.get(key); - } else { - configuration.put(key, ""); - return ""; - } - } + public static String getConfigurationParameter(String key) { + if (configuration.containsKey(key)) { + return configuration.get(key); + } else { + configuration.put(key, ""); + return ""; + } + } - public static void commitConfigurationToFile() { + public static void commitConfigurationToFile() { - try { - Files.deleteIfExists(Paths.get(CONFIG_FILE_LOCATION + "bkup")); - try { - Files.copy(Paths.get(CONFIG_FILE_LOCATION), Paths.get(CONFIG_FILE_LOCATION + "bkup")); - } catch (IOException ioe) { - if(ioe instanceof NoSuchFileException) { - log.log(Level.FINE, "No existing configuration file--not creating backup"); - } else { - log.log(Level.WARNING, "Exception encountered while trying to create configuration file backup: {0}", ioe); - } - } - } catch (IOException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); - System.err.println("Making backup configuration file failed. Exiting without committing configuration to file"); - return; - } - try ( BufferedWriter br = new BufferedWriter(new FileWriter(Paths.get(CONFIG_FILE_LOCATION).toFile(), false))) { - configuration.forEach((key, value) -> { - try { - br.append(key + delimiter + value + "\n"); - } catch (IOException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); - } - }); + try { + Files.deleteIfExists(Paths.get(CONFIG_FILE_LOCATION + "bkup")); + try { + Files.copy(Paths.get(CONFIG_FILE_LOCATION), Paths.get(CONFIG_FILE_LOCATION + "bkup")); + } catch (IOException ioe) { + if (ioe instanceof NoSuchFileException) { + log.log(Level.FINE, "No existing configuration file--not creating backup"); + } else { + log.log(Level.WARNING, + "Exception encountered while trying to create configuration file backup: {0}", ioe); + } + } + } catch (IOException ex) { + Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); + System.err.println( + "Making backup configuration file failed. Exiting without committing configuration to file"); + return; + } + try (BufferedWriter br = new BufferedWriter(new FileWriter(Paths.get(CONFIG_FILE_LOCATION).toFile(), false))) { + configuration.forEach((key, value) -> { + try { + br.append(key + delimiter + value + "\n"); + } catch (IOException ex) { + Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); + } + }); - br.flush(); - br.close(); - } catch (FileNotFoundException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); - } catch (IOException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); - } - } + br.flush(); + br.close(); + } catch (FileNotFoundException ex) { + Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); + } catch (IOException ex) { + Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); + } + } - public static String enumerateConfiguration() { - StringBuilder sb = new StringBuilder(); - configuration.forEach((key, value) -> { - sb.append(key + delimiter + value + "\n"); - }); - return sb.toString(); - } + public static String enumerateConfiguration() { + StringBuilder sb = new StringBuilder(); + configuration.forEach((key, value) -> { + sb.append(key + delimiter + value + "\n"); + }); + return sb.toString(); + } } diff --git a/src/main/java/com/tinyplantnews/priestess/CustomLoggingLevel.java b/src/main/java/com/tinyplantnews/priestess/CustomLoggingLevel.java index 1d2f8c9..79aaf45 100644 --- a/src/main/java/com/tinyplantnews/priestess/CustomLoggingLevel.java +++ b/src/main/java/com/tinyplantnews/priestess/CustomLoggingLevel.java @@ -12,7 +12,7 @@ import java.util.logging.Level; */ public class CustomLoggingLevel extends Level { - public CustomLoggingLevel(int i) { - super("custom", i); - } + public CustomLoggingLevel(int i) { + super("custom", i); + } } diff --git a/src/main/java/com/tinyplantnews/priestess/GuildProfile.java b/src/main/java/com/tinyplantnews/priestess/GuildProfile.java index 571be7d..1607a7a 100644 --- a/src/main/java/com/tinyplantnews/priestess/GuildProfile.java +++ b/src/main/java/com/tinyplantnews/priestess/GuildProfile.java @@ -17,65 +17,60 @@ import java.util.function.BiConsumer; */ class GuildProfile { - private final Guild g; + private final Guild g; - public GuildProfile(Guild g1) { - g = g1; - } + public GuildProfile(Guild g1) { + g = g1; + } - - private HashMap customemojis = new HashMap<>(); + private HashMap customemojis = new HashMap<>(); - private HashMap approvingcustomemojis = new HashMap<>(); + private HashMap approvingcustomemojis = new HashMap<>(); - //Just so it's seekable, for the random approving emoji methods. - private ArrayList approvingcustomemojinames = new ArrayList<>(); + // Just so it's seekable, for the random approving emoji methods. + private ArrayList approvingcustomemojinames = new ArrayList<>(); - /** - * @return the customemojis - */ - public HashMap getCustomemojis() { - return customemojis; - } + /** + * @return the customemojis + */ + public HashMap getCustomemojis() { + return customemojis; + } - /** - * @param customemojis the customemojis to set - */ - public void setCustomemojis(HashMap customemojis) { - this.customemojis = customemojis; - } + /** + * @param customemojis the customemojis to set + */ + public void setCustomemojis(HashMap customemojis) { + this.customemojis = customemojis; + } - public String toFile() { - return ""; - } + public String toFile() { + return ""; + } - public String emojisToString() { - StringBuilder s = new StringBuilder(""); - customemojis.forEach((String name, Snowflake snowflake) -> { - s.append(new JKRSONTag(name, snowflake.asString())); - }); - return s.toString(); - } + public String emojisToString() { + StringBuilder s = new StringBuilder(""); + customemojis.forEach((String name, Snowflake snowflake) -> { + s.append(new JKRSONTag(name, snowflake.asString())); + }); + return s.toString(); + } - public void setApprovingEmoji(String name, Snowflake snowflake) { - approvingcustomemojis.put(name, snowflake); - approvingcustomemojinames.add(name); - } + public void setApprovingEmoji(String name, Snowflake snowflake) { + approvingcustomemojis.put(name, snowflake); + approvingcustomemojinames.add(name); + } - public int emojiCount() { - return customemojis.size(); - } + public int emojiCount() { + return customemojis.size(); + } - public int approvingEmojiCount() { - return approvingcustomemojis.size(); - } + public int approvingEmojiCount() { + return approvingcustomemojis.size(); + } - public GuildEmoji getEmojiByNumber(int i) { - return g.getGuildEmojiById( - approvingcustomemojis.get(approvingcustomemojinames - .get(i) - ) - ).block(); - } + public GuildEmoji getEmojiByNumber(int i) { + return g.getGuildEmojiById(approvingcustomemojis.get(approvingcustomemojinames.get(i))).block(); + } } diff --git a/src/main/java/com/tinyplantnews/priestess/InstantiableConfiguration.java b/src/main/java/com/tinyplantnews/priestess/InstantiableConfiguration.java index 311885b..df52fd9 100644 --- a/src/main/java/com/tinyplantnews/priestess/InstantiableConfiguration.java +++ b/src/main/java/com/tinyplantnews/priestess/InstantiableConfiguration.java @@ -31,151 +31,155 @@ import javax.swing.JOptionPane; */ public class InstantiableConfiguration { - private static String CONFIG_FILE_LOCATION = null; - public static final String CONFIG_FILE_KEY = "PRIESTESS_CONFIG"; - public static final Properties p = System.getProperties(); - public static final String DEFAULT_CONFIG_FILE_NAME = "priestessconfig.txt"; + private static String CONFIG_FILE_LOCATION = null; + public static final String CONFIG_FILE_KEY = "PRIESTESS_CONFIG"; + public static final Properties p = System.getProperties(); + public static final String DEFAULT_CONFIG_FILE_NAME = "priestessconfig.txt"; - private static HashMap configuration = new HashMap<>(); + private static HashMap configuration = new HashMap<>(); - private static final Logger log = Logger.getLogger(InstantiableConfiguration.class.getName()); + private static final Logger log = Logger.getLogger(InstantiableConfiguration.class.getName()); - public static String findConfigurationFilePath() { - if (getCONFIG_FILE_LOCATION() != null) { - return getCONFIG_FILE_LOCATION(); - } - setCONFIG_FILE_LOCATION(setConfigurationFilePath(), false); - return getCONFIG_FILE_LOCATION(); - } + public static String findConfigurationFilePath() { + if (getCONFIG_FILE_LOCATION() != null) { + return getCONFIG_FILE_LOCATION(); + } + setCONFIG_FILE_LOCATION(setConfigurationFilePath(), false); + return getCONFIG_FILE_LOCATION(); + } - private static String setConfigurationFilePath() { - String s = System.getenv(CONFIG_FILE_KEY); - if (s != null && s.length() > 0) { + private static String setConfigurationFilePath() { + String s = System.getenv(CONFIG_FILE_KEY); + if (s != null && s.length() > 0) { - return s; - } else if (p.containsKey(CONFIG_FILE_KEY)) { - return p.getProperty(CONFIG_FILE_KEY); - } - if (Files.exists(Paths.get(DEFAULT_CONFIG_FILE_NAME), LinkOption.NOFOLLOW_LINKS)) { - return DEFAULT_CONFIG_FILE_NAME; - } - //JDialog jd = new JDialog(); - //jd.add(new JLabel("Choose where to put Priestess Working Directory")); - //jd.setVisible(true); - JOptionPane.showConfirmDialog(null, "Select where cult files will be stored."); - JFileChooser jfc = new JFileChooser("Config File for Discord Cult Priestess"); - jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - int rv; - boolean approved = false; - while (!approved) { - rv = jfc.showDialog(null, "Select"); - if (rv == JFileChooser.APPROVE_OPTION) { - File f = jfc.getSelectedFile(); - if (f.isDirectory() && f.canRead() && f.canWrite()) { - p.setProperty(CONFIG_FILE_KEY, f.getAbsolutePath()); - return f.getAbsolutePath(); - } - } + return s; + } else if (p.containsKey(CONFIG_FILE_KEY)) { + return p.getProperty(CONFIG_FILE_KEY); + } + if (Files.exists(Paths.get(DEFAULT_CONFIG_FILE_NAME), LinkOption.NOFOLLOW_LINKS)) { + return DEFAULT_CONFIG_FILE_NAME; + } + // JDialog jd = new JDialog(); + // jd.add(new JLabel("Choose where to put Priestess Working Directory")); + // jd.setVisible(true); + JOptionPane.showConfirmDialog(null, "Select where cult files will be stored."); + JFileChooser jfc = new JFileChooser("Config File for Discord Cult Priestess"); + jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + int rv; + boolean approved = false; + while (!approved) { + rv = jfc.showDialog(null, "Select"); + if (rv == JFileChooser.APPROVE_OPTION) { + File f = jfc.getSelectedFile(); + if (f.isDirectory() && f.canRead() && f.canWrite()) { + p.setProperty(CONFIG_FILE_KEY, f.getAbsolutePath()); + return f.getAbsolutePath(); + } + } - } - return ""; - } + } + return ""; + } - private static final String delimiter = ": "; + private static final String delimiter = ": "; - public static void getConfigurationFromFile() { - if (CONFIG_FILE_LOCATION == null) { - setConfigurationFilePath(); - } - try { - if (Files.isDirectory(Paths.get(CONFIG_FILE_LOCATION), LinkOption.NOFOLLOW_LINKS)) { - CONFIG_FILE_LOCATION = CONFIG_FILE_LOCATION + System.getProperty("file.separator") + DEFAULT_CONFIG_FILE_NAME; - } - BufferedReader br = new BufferedReader(new FileReader(Paths.get(CONFIG_FILE_LOCATION).toFile())); - br.lines().forEach((s) -> { - String key = s.substring(0, s.indexOf(delimiter)); - if (s.length() == s.indexOf(delimiter) + delimiter.length()) { - System.out.println("read empty value for key (" + key + ") from configuration file"); - configuration.put(key, ""); - } else { - String value = s.substring(s.indexOf(delimiter) + delimiter.length()); - configuration.put(key, value); - } - }); - } catch (FileNotFoundException ex) { + public static void getConfigurationFromFile() { + if (CONFIG_FILE_LOCATION == null) { + setConfigurationFilePath(); + } + try { + if (Files.isDirectory(Paths.get(CONFIG_FILE_LOCATION), LinkOption.NOFOLLOW_LINKS)) { + CONFIG_FILE_LOCATION = CONFIG_FILE_LOCATION + System.getProperty("file.separator") + + DEFAULT_CONFIG_FILE_NAME; + } + BufferedReader br = new BufferedReader(new FileReader(Paths.get(CONFIG_FILE_LOCATION).toFile())); + br.lines().forEach((s) -> { + String key = s.substring(0, s.indexOf(delimiter)); + if (s.length() == s.indexOf(delimiter) + delimiter.length()) { + System.out.println("read empty value for key (" + key + ") from configuration file"); + configuration.put(key, ""); + } else { + String value = s.substring(s.indexOf(delimiter) + delimiter.length()); + configuration.put(key, value); + } + }); + } catch (FileNotFoundException ex) { - Logger.getLogger(InstantiableConfiguration.class.getName()).log(Level.SEVERE, "Error loading configuration file from (" + CONFIG_FILE_LOCATION + ") {0}", ex); - } - } + Logger.getLogger(InstantiableConfiguration.class.getName()).log(Level.SEVERE, + "Error loading configuration file from (" + CONFIG_FILE_LOCATION + ") {0}", ex); + } + } - /** - * @return the CONFIG_FILE_LOCATION - */ - public static String getCONFIG_FILE_LOCATION() { - return CONFIG_FILE_LOCATION; - } + /** + * @return the CONFIG_FILE_LOCATION + */ + public static String getCONFIG_FILE_LOCATION() { + return CONFIG_FILE_LOCATION; + } - /** - * @param aCONFIG_FILE_LOCATION the CONFIG_FILE_LOCATION to set - */ - public static void setCONFIG_FILE_LOCATION(String aCONFIG_FILE_LOCATION, boolean persistent) { - CONFIG_FILE_LOCATION = aCONFIG_FILE_LOCATION; - if (persistent) { - p.setProperty(CONFIG_FILE_KEY, CONFIG_FILE_LOCATION); - } + /** + * @param aCONFIG_FILE_LOCATION the CONFIG_FILE_LOCATION to set + */ + public static void setCONFIG_FILE_LOCATION(String aCONFIG_FILE_LOCATION, boolean persistent) { + CONFIG_FILE_LOCATION = aCONFIG_FILE_LOCATION; + if (persistent) { + p.setProperty(CONFIG_FILE_KEY, CONFIG_FILE_LOCATION); + } - } + } - public static void setConfigurationParameter(String key, String value) { - configuration.put(key, value); - } + public static void setConfigurationParameter(String key, String value) { + configuration.put(key, value); + } - public static String getConfigurationParameter(String key) { - if (configuration.containsKey(key)) { - return configuration.get(key); - } else { - configuration.put(key, ""); - return ""; - } - } + public static String getConfigurationParameter(String key) { + if (configuration.containsKey(key)) { + return configuration.get(key); + } else { + configuration.put(key, ""); + return ""; + } + } - public static void commitConfigurationToFile() { + public static void commitConfigurationToFile() { - try { - Files.deleteIfExists(Paths.get(CONFIG_FILE_LOCATION + "bkup")); - try { - Files.copy(Paths.get(CONFIG_FILE_LOCATION), Paths.get(CONFIG_FILE_LOCATION + "bkup")); - } catch (IOException ioe) { - log.log(Level.WARNING, "Exception encountered while trying to create confirguation file backup: {0}", ioe); - } - } catch (IOException ex) { - Logger.getLogger(InstantiableConfiguration.class.getName()).log(Level.SEVERE, null, ex); - System.err.println("Making backup configuration file failed. Exiting without committing configuration to file"); - return; - } - try ( BufferedWriter br = new BufferedWriter(new FileWriter(Paths.get(CONFIG_FILE_LOCATION).toFile(), false))) { - configuration.forEach((key, value) -> { - try { - br.append(key + delimiter + value + "\n"); - } catch (IOException ex) { - Logger.getLogger(InstantiableConfiguration.class.getName()).log(Level.SEVERE, null, ex); - } - }); + try { + Files.deleteIfExists(Paths.get(CONFIG_FILE_LOCATION + "bkup")); + try { + Files.copy(Paths.get(CONFIG_FILE_LOCATION), Paths.get(CONFIG_FILE_LOCATION + "bkup")); + } catch (IOException ioe) { + log.log(Level.WARNING, "Exception encountered while trying to create confirguation file backup: {0}", + ioe); + } + } catch (IOException ex) { + Logger.getLogger(InstantiableConfiguration.class.getName()).log(Level.SEVERE, null, ex); + System.err.println( + "Making backup configuration file failed. Exiting without committing configuration to file"); + return; + } + try (BufferedWriter br = new BufferedWriter(new FileWriter(Paths.get(CONFIG_FILE_LOCATION).toFile(), false))) { + configuration.forEach((key, value) -> { + try { + br.append(key + delimiter + value + "\n"); + } catch (IOException ex) { + Logger.getLogger(InstantiableConfiguration.class.getName()).log(Level.SEVERE, null, ex); + } + }); - br.flush(); - br.close(); - } catch (FileNotFoundException ex) { - Logger.getLogger(InstantiableConfiguration.class.getName()).log(Level.SEVERE, null, ex); - } catch (IOException ex) { - Logger.getLogger(InstantiableConfiguration.class.getName()).log(Level.SEVERE, null, ex); - } - } + br.flush(); + br.close(); + } catch (FileNotFoundException ex) { + Logger.getLogger(InstantiableConfiguration.class.getName()).log(Level.SEVERE, null, ex); + } catch (IOException ex) { + Logger.getLogger(InstantiableConfiguration.class.getName()).log(Level.SEVERE, null, ex); + } + } - public static String enumerateConfiguration() { - StringBuilder sb = new StringBuilder(); - configuration.forEach((key, value) -> { - sb.append(key + delimiter + value + "\n"); - }); - return sb.toString(); - } + public static String enumerateConfiguration() { + StringBuilder sb = new StringBuilder(); + configuration.forEach((key, value) -> { + sb.append(key + delimiter + value + "\n"); + }); + return sb.toString(); + } } diff --git a/src/main/java/com/tinyplantnews/priestess/JKRSONTag.java b/src/main/java/com/tinyplantnews/priestess/JKRSONTag.java index bba44e6..62da58a 100644 --- a/src/main/java/com/tinyplantnews/priestess/JKRSONTag.java +++ b/src/main/java/com/tinyplantnews/priestess/JKRSONTag.java @@ -10,42 +10,43 @@ package com.tinyplantnews.priestess; */ public class JKRSONTag { - public JKRSONTag(String key1, String val1) { - key = key1; - val = val1; - } + public JKRSONTag(String key1, String val1) { + key = key1; + val = val1; + } - public JKRSONTag() { - } - - /** - * @return the key - */ - public String getKey() { - return key; - } + public JKRSONTag() { + } - /** - * @param key the key to set - */ - public void setKey(String key) { - this.key = key; - } + /** + * @return the key + */ + public String getKey() { + return key; + } - /** - * @return the val - */ - public String getVal() { - return val; - } + /** + * @param key the key to set + */ + public void setKey(String key) { + this.key = key; + } - /** - * @param val the val to set - */ - public void setVal(String val) { - this.val = val; - } - private String key; - private String val; + /** + * @return the val + */ + public String getVal() { + return val; + } + + /** + * @param val the val to set + */ + public void setVal(String val) { + this.val = val; + } + + private String key; + private String val; } diff --git a/src/main/java/com/tinyplantnews/priestess/JKRowlingSON.java b/src/main/java/com/tinyplantnews/priestess/JKRowlingSON.java index a6ece4e..cf766f1 100644 --- a/src/main/java/com/tinyplantnews/priestess/JKRowlingSON.java +++ b/src/main/java/com/tinyplantnews/priestess/JKRowlingSON.java @@ -18,25 +18,25 @@ import java.util.regex.Pattern; */ public class JKRowlingSON { - public static final String TAG_PATTERN = "^\\{([a-z]*):([\\\"\\{a-z][a-z:\\}\\\"]*)\\}"; + public static final String TAG_PATTERN = "^\\{([a-z]*):([\\\"\\{a-z][a-z:\\}\\\"]*)\\}"; - public static String keyVal(String key, String val) { - return String.format("\"%s:\" \"%s\"", key, val); - } + public static String keyVal(String key, String val) { + return String.format("\"%s:\" \"%s\"", key, val); + } - private static Pattern tagPattern = Pattern.compile(TAG_PATTERN); + private static Pattern tagPattern = Pattern.compile(TAG_PATTERN); - public static JKRSONTag decode(String tag) { - Matcher m = tagPattern.matcher(tag); + public static JKRSONTag decode(String tag) { + Matcher m = tagPattern.matcher(tag); - JKRSONTag db = new JKRSONTag(); - if (m.matches()) { - db.setKey(m.group(1)); - db.setVal(m.group(2)); - } else { - Logger.getLogger(JKRowlingSON.class.toString()).log(Level.SEVERE, "Could not decode " + tag); - } - return db; - } + JKRSONTag db = new JKRSONTag(); + if (m.matches()) { + db.setKey(m.group(1)); + db.setVal(m.group(2)); + } else { + Logger.getLogger(JKRowlingSON.class.toString()).log(Level.SEVERE, "Could not decode " + tag); + } + return db; + } } diff --git a/src/main/java/com/tinyplantnews/priestess/MessageStore.java b/src/main/java/com/tinyplantnews/priestess/MessageStore.java index dd87990..256fb81 100644 --- a/src/main/java/com/tinyplantnews/priestess/MessageStore.java +++ b/src/main/java/com/tinyplantnews/priestess/MessageStore.java @@ -17,121 +17,134 @@ import java.util.logging.Level; import java.util.logging.Logger; /** - * + * OH IT STORES THE PROPHECIES + * + * The configuration file (priestessconfig.txt) contains a key, 'messages', for which the value is a path to the messages store. + * The messages store contains prophecies that are given every few bean goose invocations. + * This class first loads the file, scans it and generates a list of indices for the messages it contains. + * + * This class could definitely use a cache of the message starts--a special block at the beginning/end of the file with a list of message starts/ends, + * but I'm not up to writing that today - 7 May 2023 + * * @author atomb */ public class MessageStore { - private RandomAccessFile f; - private long filelength = 0; - private FileChannel fr = null; + private RandomAccessFile f; + private long filelength = 0; + private FileChannel fr = null; - private MessageCacher mc; + private MessageCacher mc; - private int[] messagestarts = null; - Thread t; + private int[] messagestarts = null; + Thread t; - private boolean messagesCached = false; + private boolean messagesCached = false; + private long loadStart = Long.MAX_VALUE; - public MessageStore(File f1) throws FileNotFoundException, IOException { - f = new RandomAccessFile(f1.getPath(), "r"); - System.out.println("Message store is " + f.length() + " bytes long"); - fr = f.getChannel(); - filelength = f.length(); - mc = new MessageCacher(); - t = new Thread(mc); - t.start(); - } + public MessageStore(File f1) throws FileNotFoundException, IOException { + loadStart = System.nanoTime(); + f = new RandomAccessFile(f1.getPath(), "r"); + System.out.println("Message store is " + f.length() + " bytes long"); + fr = f.getChannel(); + filelength = f.length(); + mc = new MessageCacher(); + t = new Thread(mc); + t.start(); + } - public String messageAt(int i) { - waitUntilLoaded(); + public String messageAt(int i) { + waitUntilLoaded(); - int start = messagestarts[i]; - StringBuilder s = new StringBuilder(); + int start = messagestarts[i]; + StringBuilder s = new StringBuilder(); - try { - f.seek(start); - int a = 0; - int j = 0; - char c = '\0'; + try { + f.seek(start); + int a = 0; + int j = 0; + char c = '\0'; - while ((j = f.read()) != -1 && ((char) j != '}')) { - c = (char) j; - s.append(c); - a++; - } + while ((j = f.read()) != -1 && ((char) j != '}')) { + c = (char) j; + s.append(c); + a++; + } - } catch (IOException ex) { - Logger.getLogger(MessageStore.class.getName()).log(Level.SEVERE, null, ex); - } + } catch (IOException ex) { + Logger.getLogger(MessageStore.class.getName()).log(Level.SEVERE, null, ex); + } - while (s.charAt(0) == '{') { - s.deleteCharAt(0); - } + while (s.charAt(0) == '{') { + s.deleteCharAt(0); + } - return s.toString(); - } + return s.toString(); + } - public String randomMessage() { - return messageAt((int) (messagestarts.length * Math.random())); - } + public String randomMessage() { + return messageAt((int) (messagestarts.length * Math.random())); + } - boolean messagesAvailable() { - return messagesCached; - } + boolean messagesAvailable() { + return messagesCached; + } - void waitUntilLoaded() { - if (t.isAlive()) { - try { - t.join(); - } catch (InterruptedException ex) { - Logger.getLogger(MessageStore.class.getName()).log(Level.SEVERE, null, ex); - } - } - } + void waitUntilLoaded() { + if (t.isAlive()) { + try { + t.join(); + } catch (InterruptedException ex) { + Logger.getLogger(MessageStore.class.getName()).log(Level.SEVERE, null, ex); + } + } + } - public int messageCount() { - return messagestarts.length; - } + public int messageCount() { + return messagestarts.length; + } - private class MessageCacher implements Runnable { + private class MessageCacher implements Runnable { - @Override - public void run() { - Logger log = Logger.getLogger(this.getClass().getName()); - log.setLevel(Level.FINE); - log.log(Level.INFO, "Attempting to characterize message store"); - try { - ArrayList messagestartsal = new ArrayList<>(); //contains index of every '{' - char c; - int a = 0; - int i = 0; - int j = 0; - ByteBuffer b = ByteBuffer.allocate(20); - b.rewind(); - log.log(Level.INFO, "Starting to characterize message store at position (" + fr.position() - + ") with channel size " + fr.size()); - while ((j = f.read()) != -1) { - c = (char) j; - if (c == '{') { - messagestartsal.add(a); + @Override + public void run() { + Logger log = Logger.getLogger(this.getClass().getName()); + log.setLevel(Level.FINE); + log.log(Level.INFO, "Attempting to characterize message store"); + try { + ArrayList messagestartsal = new ArrayList<>(); // contains index of every '{' + char c; + int a = 0; + int i = 0; + int j = 0; + ByteBuffer b = ByteBuffer.allocate(20); + b.rewind(); + log.log(Level.INFO, "Starting to characterize message store at position (" + fr.position() + + ") with channel size " + fr.size()); + while ((j = f.read()) != -1) { + c = (char) j; + if (c == '{') { + messagestartsal.add(a); - } - a++; - } - Integer[] messagestarts1 = messagestartsal.toArray(new Integer[0]); - messagestarts = new int[messagestarts1.length]; - for (i = 0; i < messagestarts1.length; i++) { - messagestarts[i] = messagestarts1[i].intValue(); - } - } catch (IOException ex) { - Logger.getLogger(MessageStore.class.getName()).log(Level.SEVERE, null, ex); - } - for (int i : messagestarts) { - System.out.println("Found invocation message at position " + i); - } - messagesCached = true; - } + } + a++; + } + Integer[] messagestarts1 = messagestartsal.toArray(new Integer[0]); + messagestarts = new int[messagestarts1.length]; + for (i = 0; i < messagestarts1.length; i++) { + messagestarts[i] = messagestarts1[i].intValue(); + } + } catch (IOException ex) { + Logger.getLogger(MessageStore.class.getName()).log(Level.SEVERE, null, ex); + } + for (int i : messagestarts) { + System.out.println("Found invocation message at position " + i); + } + messagesCached = true; - } + long loadEnd = System.nanoTime(); + long tdiff = loadEnd - loadStart; + log.log(Level.FINE, "Prophecies loaded in {0} ms", tdiff); + } + } } diff --git a/src/main/java/com/tinyplantnews/priestess/Priestess.java b/src/main/java/com/tinyplantnews/priestess/Priestess.java index 992cedd..18be656 100644 --- a/src/main/java/com/tinyplantnews/priestess/Priestess.java +++ b/src/main/java/com/tinyplantnews/priestess/Priestess.java @@ -1,4 +1,6 @@ /* +:q:q +qqqqqqqq:qdf * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license * Click nbfs://nbhost/SystemFileSystem/Templates/Project/Maven2/JavaApp/src/main/java/${packagePath}/${mainClassName}.java to edit this template */ @@ -46,818 +48,814 @@ import reactor.core.publisher.Mono; */ public class Priestess { - public static String magicPhrase = "bean goose"; + public static String magicPhrase = "bean goose"; - public static String cultChannelName = "bean-goose"; + public static String cultChannelName = "bean-goose"; - private static void trySetDebugLevel(String level) { - try { - debug_level = Integer.parseInt(level); - log.setLevel(new CustomLoggingLevel(debug_level)); - log.log(Level.INFO, "Logging level set to {0}", level); - } catch (NumberFormatException nfe) { - log.log(Level.WARNING, "Invalid custom logging level ({0})", level); - } - } + private static void trySetDebugLevel(String level) { + try { + Level new_debug_level = Level.parse(level); + log.setLevel(new_debug_level); + debug_level = new_debug_level.intValue(); + log.log(Level.INFO, "Logging level set to {0}", level); + } catch (NumberFormatException nfe) { + log.log(Level.WARNING, "Invalid custom logging level ({0})", level); + } + } - private static String botToken = ""; + private static String botToken = ""; - private ReactionEmoji good; + private ReactionEmoji good; - GatewayDiscordClient dc; - - static HashMap guildnames = new HashMap<>(); - static Map guildemojimaps = new HashMap<>(); - - private ArrayList cultableChannelIDs = new ArrayList<>(); - - public static final int MAX_PERMS = Integer.MAX_VALUE; - - public static final int LOCAL_PERMS = MAX_PERMS - 1; - - public static final String WHITELIST = "whitelist"; - public static final String CATLIST = "catlist"; - - private BufferedReader user_reader; - - public static final String MESSAGES = "messages"; - public static final String TESTSUITE = "testsuite"; - - private MessageStore ms = null; - - public static final String DEBUG_LEVEL = "debug_level"; - - public static String NEWLINE = System.getProperty("line.separator"); - - private static final int default_debug_level = Level.INFO.intValue(); - private static int debug_level = default_debug_level; - - private static final Logger log = Logger.getLogger(Priestess.class.getName()); - - private static boolean allChannelsCultable = false; - - private String[] approvingEmojis = { - "U+1F44D", - "U+270C", - "U+1F525", - "U+2764", - "U+1F496", - "U+1F63B" - }; - - private int invocationsThisSession = 0; - - public static void main(String[] args) { - - for (int i = 0; i < args.length; i++) { - - if (args[i] == TESTSUITE) { - return; - } - - if (args[i].startsWith("--")) { - System.out.println("Command-line switch (" + args[i] + ") detected."); - switch (args[i].substring(2)) { - case "config-file": - i++; - Configuration.setCONFIG_FILE_LOCATION(args[i], false); - break; - case "config-file-persistent": - i++; - Configuration.setCONFIG_FILE_LOCATION(args[i], true); - break; - case "debug-level": - i++; - Configuration.setConfigurationParameter(DEBUG_LEVEL, args[i]); - trySetDebugLevel(args[i]); - break; - //There is precisely no reason for me to include this. - case "windows-lineendings": - NEWLINE = "\r\n"; - break; - case "allchannels": - allChannelsCultable = true; - log.log(Level.INFO, "Listening to all channels in joined guilds."); - break; - default: - - } - } - } - - new Priestess().start(); - } - - private String randomApprovingEmoji() { - return approvingEmojis[(int) Math.floor((Math.random() * approvingEmojis.length))]; - } - - private void registerEmoji(Guild g, Snowflake emojiFlake, String emojiName) { - System.out.println(String.format("\nCustom Emoji Detected: \nServer:\t%s\nFlake:\t%s\nName:\t%s", g, emojiFlake, emojiName)); - if (!guildemojimaps.containsKey(g)) { - guildemojimaps.put(g, new GuildProfile(g)); - } - guildemojimaps.get(g).getCustomemojis().put(emojiName, emojiFlake); - - } - - private String cdr(String needle, String haystack) { - if (haystack.startsWith(needle)) { - return haystack.substring(needle.length()).trim(); - } else { - return haystack; - } - } - - /** - * I hope it needs not be said, but commands must be unique. - * - * @param t - * @param m - * @param c - * @return - */ - private Publisher dispatchCommand(MessageCreateEvent t, Message m, String c) { - int permissionLevel = resolveAuthorPermissionLevel(t, m); - - return dispatchCommand(t, m, c, permissionLevel); - } - - private Publisher dispatchCommand(MessageCreateEvent t, Message m, String c, int permissionLevel) { - String commandline = cdr(magicPhrase, c); - System.out.println("Attempting to run command (" + commandline + ") with permission level " + permissionLevel); - - Command.tryAll(commandline, m, permissionLevel); //System.out.println("payload " + payload); - return Mono.empty(); - } - - Function> guildedmessagehandler = (MessageCreateEvent t) -> { - Message m = t.getMessage(); - String c = m.getContent(); - Snowflake cid = m.getChannel().block().getId(); - - if (allChannelsCultable || cultableChannelIDs.contains(cid)) { - - Guild g = m.getGuild().block(); - GuildProfile gp = guildemojimaps.get(g); - if (gp == null) { - log.log(Level.INFO, - "Message from unregistered guild, " - + "not registering now."); - //register guild? - return Mono.empty(); - } - - if (c.equalsIgnoreCase(magicPhrase)) { - invokeDeity(g, m); - } else if (c.startsWith(magicPhrase)) { - return dispatchCommand(t, m, c); - } - } - return Mono.empty(); - }; - - Function> directmessagehandler = (var t) -> { - //System.out.println("ya boi"); - Message m = t.getMessage(); - String c = m.getContent(); - log.log(Level.FINE, "processing direct message {0}", c); - - log.log(Level.FINE, "User snowflake for message {0} is {1}", new Object[]{c, m.getAuthor().get().getId().asString()}); - - if (c.equalsIgnoreCase(magicPhrase)) { - //System.out.println("approved"); - m.addReaction(ReactionEmoji.codepoints(randomApprovingEmoji())).subscribe(); - } else if (c.startsWith(magicPhrase)) { - return dispatchCommand(t, m, c); - } - return Mono.empty(); - }; - - private static final String alphabet = "abcdefghijklmnopqrstuvwxyz"; - - private String randomLetter() { - return "" + alphabet.charAt((int) (Math.random() * alphabet.length())); - } - - private HashMap flywheel = new HashMap<>(); - - private void start() { - if (debug_level != default_debug_level) { - log.log(Level.INFO, String.format("Starting Priestess with debug level {0}", debug_level)); - } else { - log.log(Level.INFO, String.format("Starting Priestess normally")); - } - setup(); - if(botToken.isBlank()) { - log.log(Level.SEVERE, "bot token is null. aborting."); - return; - } - dc = DiscordClientBuilder.create(botToken).build().login().block(); - if (dc == null) { - log.log(Level.SEVERE, "gatewaydiscordclient was null. aborting."); - return; - } - String boot_time = ""; - Date d = new Date(); - SimpleDateFormat df = new SimpleDateFormat("dd MMM YYYY kk:mm"); - boot_time = df.format(d); - dc.updatePresence(ClientPresence.of(Status.ONLINE, ClientActivity.playing("since " + boot_time))).subscribe(); - dc.getGuilds().flatMap((g) -> { - if (!guildemojimaps.containsKey(g)) { - guildemojimaps.put(g, new GuildProfile(g)); - } - - if (!guildnames.containsKey(g.getName())) { - guildnames.put(g.getName(), g); - } - return Mono.empty(); - } - ).subscribe(); - - dc.getGuilds().flatMap((g) - -> g.getChannels().flatMap((channel) -> { - - log.log(Level.INFO, "Checking cultability of channel {0}", channel.getName()); - if (channel.getName().equals(cultChannelName)) { - System.out.println("Channel " + channel.getName() + " in " + g.getName() + " is cultable"); - cultableChannelIDs.add(channel.getId()); - } - return Mono.empty(); - }) - ).subscribe(); - - dc.getGuilds().flatMap(g -> g.getEmojis()).flatMap(g2 -> { - //system.out.println("emoji"); - registerEmoji(g2.getGuild().block(), g2.getId(), g2.getName()); - return Mono.empty(); - } - ).subscribe(); - - dc.on(ConnectEvent.class, event -> { - - log.log(Level.INFO, "connected"); - - return Mono.empty(); - }).subscribe(); - - dc.on(ChatInputInteractionEvent.class).flatMap(event -> { - return event.reply().withContent("agreed"); - }).subscribe(); - - SysInListener sil = new SysInListener(); - Thread t = new Thread(sil); - - t.start(); - flywheel.put("System.in listener", t); - - dc.on(MessageCreateEvent.class).filter(event -> !event.getMessage().getAuthor().get().isBot()) - .filter(g -> !g.getGuild().blockOptional().isEmpty()).flatMap(guildedmessagehandler) - .subscribe(); - - dc.on(MessageCreateEvent.class).filter(event -> !event.getMessage().getAuthor().get().isBot()) - .filter(g -> g.getGuild().blockOptional().isEmpty()).flatMap(directmessagehandler) - .blockLast(); - } - - private int invocationsBeforeThisSession = 0; - - private void setup() { - Configuration.findConfigurationFilePath(); - Configuration.getConfigurationFromFile(); - - botToken = Configuration.getConfigurationParameter(TOKEN_KEY); - - String previousInvocations = Configuration.getConfigurationParameter(INVOCATIONS_KEY); - try { - if (previousInvocations.isBlank()) { - previousInvocations = "0"; - } - invocationsBeforeThisSession = Integer.parseInt(previousInvocations); - } catch (NumberFormatException nfe) { - System.err.println("Error reading invocations from last boot."); - Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, nfe.getMessage()); - System.out.println("Invocations this boot: " + invocationsThisSession); - System.out.println("Invocation count from configuration file: " + previousInvocations); - } - - user_reader = new BufferedReader(new InputStreamReader(System.in)); - - setupWhiteList(); - - ms = setupMessageStore(); - - long free0 = Runtime.getRuntime().freeMemory(); - log.log(Level.FINE, "Initialization complete. approx. {0} bytes free in memory.\n Attempting garbage collection.", free0); - Runtime.getRuntime().gc(); - long free1 = Runtime.getRuntime().freeMemory(); - long freediff = free1 - free0; - log.log(Level.FINE, "Post-initialization garbage collection freed ", freediff); - registerDefaultCommands(); - } - - boolean replcontinue = true; - - public static final String TOKEN_KEY = "token"; - public static final String INVOCATIONS_KEY = "invocations"; - - private void shutdown() { - replcontinue = false; - dc.logout().subscribe(); - System.out.println("Logged out"); - try { - user_reader.close(); - } catch (IOException ex) { - Logger.getLogger(Priestess.class.getName()).log(Level.SEVERE, null, ex); - } - for (Thread t : flywheel.values()) { - t.interrupt(); - } - - int invocationsTotal = invocationsBeforeThisSession + invocationsThisSession; - System.out.println("Bean Goose has been invoked " + invocationsTotal + " times so far."); - Configuration.setConfigurationParameter(INVOCATIONS_KEY, Integer.toString(invocationsTotal)); - Configuration.commitConfigurationToFile(); - System.out.println("Configuration committed to file."); - } - - private void invokeDeity(Guild g, Message m) { - int ae_custom = guildemojimaps.get(g).approvingEmojiCount(); - int emojicount = approvingEmojis.length + ae_custom; - //System.out.println(approvingEmojis.length + " default, " + ae_custom + " custom approving emojis."); - int which = (int) (Math.random() * emojicount); - if (which < approvingEmojis.length) { - m.addReaction(ReactionEmoji.codepoints(randomApprovingEmoji())).subscribe(); - } else { - which -= approvingEmojis.length; - m.addReaction(ReactionEmoji.custom(guildemojimaps.get(g).getEmojiByNumber(which))).subscribe(); - } - invocationsThisSession++; - - dispatchMilestone(invocationsThisSession + invocationsBeforeThisSession, g, m); - - } - - private HashMap rolewhitelist = new HashMap<>(); - - private int resolveAuthorPermissionLevel(MessageCreateEvent t, Message m) { - int level = 0; - Optional gio = t.getGuildId(); - if (gio.isPresent()) { - Member a = m.getAuthorAsMember().block(); - for (Snowflake snowflake : (Snowflake[]) a.getRoleIds().toArray(new Snowflake[3])) { - if (rolewhitelist.containsKey(snowflake)) { - int candy = rolewhitelist.get(snowflake).intValue(); - if (candy > level) { - level = candy; - } - } - } - } - - User a = m.getAuthor().get(); - Snowflake aid = a.getId(); - if (rolewhitelist.containsKey(aid)) { - int candy = rolewhitelist.get(aid).intValue(); - if (candy > level) { - level = candy; - } - } - - if (fromCatluck(m)) { - level = MAX_PERMS; - } - return level; - } - - private boolean fromCatluck(Message m) { - String s = Configuration.getConfigurationParameter(CATLIST); - Optional ao = m.getAuthor(); - if (ao.isPresent()) { - for (String s1 : s.split(" ")) { - if (s1.equals(ao.get().getId().asString())) { - System.out.println("Literally catluck detected."); - return true; - } - } - } - return false; - } - - private void dispatchMilestone(int i, Guild g, Message m) { - if ((i % 5) == 0) { - MessageCreateSpec mcs = MessageCreateSpec.create() - .withMessageReference(m.getId()) - .withContent(randomMessage()); - m.getChannel().block().createMessage(mcs).subscribe(); - } - } - - private ArrayList messages = new ArrayList<>(); - - private String randomMessage() { - if (ms.messagesAvailable()) { - return ms.randomMessage(); - } - if (messages.isEmpty()) { - return "bean goose approves"; - } - return messages.get((int) (Math.random() * messages.size())); - } - - private void setupWhiteList() { - String rolelist = Configuration.getConfigurationParameter(WHITELIST); - if (!rolelist.isBlank()) { - - String subtokenDelimiter = "/"; - - String[] tokens = rolelist.split(" "); - for (String token : tokens) { - - String sflake = token.substring(0, token.indexOf(subtokenDelimiter)); - String perm = token.substring(token.indexOf(subtokenDelimiter) + subtokenDelimiter.length(), token.length()); - - System.out.println("Adding snowflake (" + sflake + ") to whitelist with permission level (" + perm + ")."); - - Snowflake a = Snowflake.of(sflake); - - rolewhitelist.put(a, Integer.parseInt(perm)); - } - } - } - - private MessageStore setupMessageStore() { - String mesglist = Configuration.getConfigurationParameter(MESSAGES); - File f = Paths.get(mesglist).toFile(); - try { - MessageStore ms1 = new MessageStore(f); - return ms1; - } catch (IOException e) { - if (!f.exists()) { - - } else { - log.log(Level.SEVERE, e.getMessage()); - } - } - return null; - } - - private void reloadMessageStore() { - MessageStore ms1 = setupMessageStore(); - ms1.waitUntilLoaded(); - ms = ms1; - } - - private Guild resolveGuildByNameOrId(String token) { - log.log(Level.INFO, "Finding guild by name or ID " + token); - if (guildnames.containsKey(token)) { - return guildnames.get(token); - } - return this.dc.getGuildById(Snowflake.of(token)).block(); - } - - private class SysInListener implements Runnable { - - @Override - public void run() { - try { - while (replcontinue) { - while (!user_reader.ready()) { - Thread.sleep(1000); - if (!replcontinue) { - user_reader.close(); - return; - } - } - String a = user_reader.readLine(); - dispatchCommand(null, null, a, LOCAL_PERMS); - } - user_reader.close(); - } catch (IOException ex) { - Logger.getLogger(Priestess.class.getName()).log(Level.SEVERE, null, ex); - } catch (InterruptedException ex) { - Logger.getLogger(this.getClass().getName()).log(Level.INFO, "System.in Listener interrupted."); - } - System.out.println("break repl"); - } - - } - - private static void tryPush(ArrayList a, StringBuilder s) { - if (!s.isEmpty()) { - a.add(s.toString()); - } - } - - public static String[] tokenize(String payload) { - ArrayList a = new ArrayList<>(); - StringBuilder s = new StringBuilder(); - boolean inQuote = false; - for (char c : payload.toCharArray()) { - //log.log(Level.FINE, String.format("c: %c, inQuote: %s", c, (inQuote ? "yes" : "no"))); - if (!inQuote && c == '\"') { - inQuote = true; - tryPush(a, s); - s.delete(0, s.length()); - } else if (inQuote && c == '\"') { - inQuote = false; - tryPush(a, s); - s.delete(0, s.length()); - } else if (!inQuote && c == ' ') { - tryPush(a, s); - s.delete(0, s.length()); - } else { - s.append(c); - } - } - tryPush(a, s); - if (inQuote) { - log.log(Level.WARNING, "Unterminated quote passed to tokenizer"); - return null; - } - return a.toArray(new String[a.size()]); - } - - /** - * I wanted the replacement string to be {xxxx} without the dollar sign, but - * unit tests failed when the help/usage was nothing but {xxxx}. Instead of - * investigating, I gave up and added a dollar sign to make it something - * like Python's f-strings. Or JS' backtick-strings, I can never remember - * which is which. - */ - public static class Callback implements Function> { - - final Logger log = Logger.getLogger(Callback.class.getName()); - String[] usages = {"Undefined command usage"}; - String help = "${usage}"; - - @Override - public Publisher apply(CommandArgs t) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody - } - - public String getHelp(String commandName) { - String s = getUsage(commandName); - return help/*.replaceAll("\\$\\{usage\\}", s)*/.replaceAll("\\$\\{commandname\\}", commandName); - } - - public String getUsage(String commandName) { - StringBuilder u = new StringBuilder(); - for (int i = 0; i < usages.length; i++) { - String s = usages[i]; - s.replaceAll("\\$\\{commandname\\}", commandName); - u.append(s); - if (i != usages.length - 1) { - u.append(NEWLINE); - } - } - return u.toString(); - } - - } - - public final Callback registerEmojiCommand = new Callback() { - - String usage = "{commandname} EMOJI"; - String help - = "register emoji for use in basic invocations." - + "" - + "" - + "" - + ""; - - @Override - public Publisher apply(CommandArgs o) { - String[] tokens = tokenize(o.getPayload()); - String emojiname = tokens[0]; - - Guild g; - if (tokens.length == 3 && "in".equals(tokens[1])) { - g = resolveGuildByNameOrId(tokens[2]); - } else { - if (o.getMessage() != null) { - g = o.getMessage().getGuild().block(); - } else { - o.replyWith("Could not determine what guild to register emoji with."); - return null; - } - } - - Snowflake s = (Snowflake) guildemojimaps.get(g).getCustomemojis().get(emojiname); - - if (s != null) { - - GuildEmoji emoji = g.getGuildEmojiById(s).block(); - o.getMessage().addReaction(ReactionEmoji.custom(emoji)).subscribe(); - guildemojimaps.get(o.getMessage().getGuild().block()).setApprovingEmoji(emoji.getName(), emoji.getId()); - } else { - log.log(Level.WARNING, "tried registering emoji ''{0}'' but no dice", emojiname); - } - return null; - } - }; - - public final Callback commitConfigurationCommand = new Callback() { - @Override - public Publisher apply(CommandArgs o) { - System.out.println("Committing configuration to file."); - Configuration.commitConfigurationToFile(); - return Mono.empty(); - } - }; - - /** - * Show system status - */ - public final Callback showCommand = new Callback() { - @Override - public Publisher apply(CommandArgs o) { - System.out.println("System Status:"); - guildemojimaps.forEach((guild, gp) -> { - System.out.println("\n" + guild.getName() + ":"); - gp.getCustomemojis().forEach((name, snow) -> { - System.out.println("\n\t" + name + ": " + snow.asString()); - }); - }); - log.log(Level.INFO, "Configuration file location is " + Configuration.getCONFIG_FILE_LOCATION()); - return Mono.empty(); - } - }; - - public final Callback setConfigCommand = new Callback() { - @Override - public Publisher apply(CommandArgs o) { - String pay2 = cdr("set", o.getPayload()); - String[] paytokens = pay2.split(" "); - if (paytokens.length == 2) { - log.log(Level.INFO, "setting configuration parameter " + paytokens[0] + " to " + paytokens[1]); - Configuration.setConfigurationParameter(paytokens[0], paytokens[1]); - } else { - log.log(Level.INFO, "Invalid argument count for set configuration parameter command"); - } - return Mono.empty(); - } - }; - - public final Callback showConfigCommand = new Callback() { - @Override - public Publisher apply(CommandArgs o) { - log.log(Level.INFO, "Showing configuration."); - log.log(Level.INFO, Configuration.enumerateConfiguration()); - return Mono.empty(); - } - }; - - public final Callback permissionLevelCommand = new Callback() { - @Override - public Publisher apply(CommandArgs o) { - o.replyWith(String.format("Your permission level in this context is %s", o.getPermCalledWith())); - return Mono.empty(); - } - }; - - public final Callback setCultableChannelsCommand = new Callback() { - @Override - public Publisher apply(CommandArgs o) { - String p = o.getPayload(); - if (p.isBlank()) { - o.replyWith("Culting all channels"); - allChannelsCultable = true; - } else { - String[] tokens = tokenize(p); - if (isAffirmative(tokens[0])) { - o.replyWith("Culting all channels"); - allChannelsCultable = true; - } else if (isNegatory(tokens[0])) { - o.replyWith("Removing all-channel cult"); - allChannelsCultable = false; - } else if (tokens.length >= 2) { - Guild g = resolveGuildByNameOrId(tokens[0]); - if (g != null) { - GuildChannel c = g.getChannels().filter(new Predicate() { - @Override - public boolean test(GuildChannel t) { - return t.getName().equals(tokens[1]); - } - }).blockFirst(); - if (g != null) { - if (tokens.length == 3) { - if (isAffirmative(tokens[2])) { - cultableChannelIDs.add(c.getId()); - o.replyWith("Adding channel to cultable channels list"); - } else if (isNegatory(tokens[2])) { - o.replyWith("Removing channel from cultable channels list"); - cultableChannelIDs.remove(c); - } else { - o.replyWith("Could not determine whether to cult or uncult channel."); - } - } - } else { - o.replyWith("Could not resolve channel to cult or uncult."); - } - } - } else { - o.replyWith("Unknown parameters for command"); - } - } - return Mono.empty(); - } - - private boolean isAffirmative(String token) { - return "yes".equalsIgnoreCase(token); - } - - private boolean isNegatory(String token) { - return "no".equalsIgnoreCase(token); - } - }; - - public final Callback shutdownCommand = new Callback() { - @Override - public Publisher apply(CommandArgs o) { - log.log(Level.INFO, "Shutting down."); - shutdown(); - return Mono.empty(); - } - }; - - public final Callback l = new Callback() { - @Override - public Publisher apply(CommandArgs o) { - - String[] arglist = o.getPayload().split(" "); - if (arglist.length != 2) { - - return Mono.empty(); - } - Snowflake s = Snowflake.of(arglist[0]); - return Mono.empty(); - } - }; - - public final Callback sendToCommand = new Callback() { - @Override - public Publisher apply(CommandArgs o) { - - String[] arglist = o.getPayload().split(" "); - if (arglist.length < 3) { - o.replyWith("Not enough arguments."); - return Mono.empty(); - } - Guild a = resolveGuildByNameOrId(arglist[0]); - //guildnames.get(arglist[0]); - /* - for (Object a0 : guildnames.entrySet().toArray()) { - Map.Entry a3 = (Map.Entry) a0; - Guild a1 = (Guild) a3.getValue(); - if (a1.getId().asString().equals(arglist[0])) { - a = a1; - } - }*/ - - if (a == null) { - o.replyWith("Could not find guild"); - return Mono.empty(); - } - a.getChannels().flatMap((ch) -> { - if (ch.getName().equals(arglist[1])) { - String argrest = ""; - for (int i = 2; i < arglist.length; i++) { - argrest += arglist[i] + " "; - } - argrest = argrest.substring(0, argrest.length() - 1); - TextChannel ch2 = (TextChannel) ch; - MessageCreateSpec mcs = MessageCreateSpec.create().withContent(argrest); - ch2.createMessage(mcs).subscribe(); - } - return Mono.empty(); - }).blockLast(); - return Mono.empty(); - } - }; - - public final Callback reloadMessageStoreCommand = new Callback() { - @Override - public Publisher apply(CommandArgs o) { - log.log(Level.INFO, "Attempting to reload messages."); - reloadMessageStore(); - log.log(Level.INFO, "Messages reloaded, {0} in registry.", ms.messageCount()); - return Mono.empty(); - } - }; - - private void registerDefaultCommands() { - Command.registerCommand(new Command("status", 1).setCallback(showCommand)); - Command.registerCommand(new Command("reload messages", 1).setCallback(reloadMessageStoreCommand)); - Command.registerCommand(new Command("use emoji", 1).setCallback(registerEmojiCommand)); - Command.registerCommand(new Command("show config", 1).setCallback(showConfigCommand)); - Command.registerCommand(new Command("set", 1).setCallback(setConfigCommand)); - Command.registerCommand(new Command("shutdown", 50).setCallback(shutdownCommand)); - Command.registerCommand(new Command("send to", 1).setCallback(sendToCommand)); - Command.registerCommand(new Command("cult", 9000).setCallback(setCultableChannelsCommand)); - Command.registerCommand(new Command("perm", 0).setCallback(permissionLevelCommand)); - Command.registerCommand(Command.commandThatJustRepliesWith("is minecraft online", "i dunno log on and find out smfh")); - - } + GatewayDiscordClient dc; + + static HashMap guildnames = new HashMap<>(); + static Map guildemojimaps = new HashMap<>(); + + private ArrayList cultableChannelIDs = new ArrayList<>(); + + public static final int MAX_PERMS = Integer.MAX_VALUE; + + public static final int LOCAL_PERMS = MAX_PERMS - 1; + + public static final String WHITELIST = "whitelist"; + public static final String CATLIST = "catlist"; + + private BufferedReader user_reader; + + public static final String MESSAGES = "messages"; + public static final String TESTSUITE = "testsuite"; + + private MessageStore ms = null; + + public static final String DEBUG_LEVEL = "debug_level"; + + public static String NEWLINE = System.getProperty("line.separator"); + + private static final int default_debug_level = Level.INFO.intValue(); + private static int debug_level = default_debug_level; + + private static final Logger log = Logger.getLogger(Priestess.class.getName()); + + private static boolean allChannelsCultable = false; + + private String[] approvingEmojis = { "U+1F44D", "U+270C", "U+1F525", "U+2764", "U+1F496", "U+1F63B" }; + + private int invocationsThisSession = 0; + + public static void main(String[] args) { + + for (int i = 0; i < args.length; i++) { + + if (args[i] == TESTSUITE) { + return; + } + + if (args[i].startsWith("--")) { + System.out.println("Command-line switch (" + args[i] + ") detected."); + String yarg = args[i].substring(2, args[i].indexOf('=')); + switch (yarg) { + case "config-file": + Configuration.setCONFIG_FILE_LOCATION(yarg, false); + i++; + break; + case "config-file-persistent": + Configuration.setCONFIG_FILE_LOCATION(yarg, true); + i++; + break; + case "debug-level": + String newlevel = args[i].substring(args[i].indexOf('=')+1); + Configuration.setConfigurationParameter(DEBUG_LEVEL, newlevel); + trySetDebugLevel(newlevel); + i++; + break; + case "debug": + Configuration.setConfigurationParameter(DEBUG_LEVEL, Level.ALL.toString()); + trySetDebugLevel(yarg); + i++; + break; + // There is precisely no reason for me to include this. + case "windows-lineendings": + NEWLINE = "\r\n"; + break; + case "allchannels": + allChannelsCultable = true; + log.log(Level.INFO, "Listening to all channels in joined guilds."); + break; + default: + log.log(Level.INFO, "Unknown command-line argument: {0}", yarg); + } + } + } + + new Priestess().start(); + } + + private String randomApprovingEmoji() { + return approvingEmojis[(int) Math.floor((Math.random() * approvingEmojis.length))]; + } + + private void registerEmoji(Guild g, Snowflake emojiFlake, String emojiName) { + System.out.println(String.format("\nCustom Emoji Detected: \nServer:\t%s\nFlake:\t%s\nName:\t%s", g, emojiFlake, + emojiName)); + if (!guildemojimaps.containsKey(g)) { + guildemojimaps.put(g, new GuildProfile(g)); + } + guildemojimaps.get(g).getCustomemojis().put(emojiName, emojiFlake); + + } + + private String cdr(String needle, String haystack) { + if (haystack.startsWith(needle)) { + return haystack.substring(needle.length()).trim(); + } else { + return haystack; + } + } + + /** + * I hope it needs not be said, but commands must be unique. + * + * @param t + * @param m + * @param c + * @return + */ + private Publisher dispatchCommand(MessageCreateEvent t, Message m, String c) { + int permissionLevel = resolveAuthorPermissionLevel(t, m); + + return dispatchCommand(t, m, c, permissionLevel); + } + + private Publisher dispatchCommand(MessageCreateEvent t, Message m, String c, int permissionLevel) { + String commandline = cdr(magicPhrase, c); + System.out.println("Attempting to run command (" + commandline + ") with permission level " + permissionLevel); + + Command.tryAll(commandline, m, permissionLevel); // System.out.println("payload " + payload); + return Mono.empty(); + } + + Function> guildedmessagehandler = (MessageCreateEvent t) -> { + Message m = t.getMessage(); + String c = m.getContent(); + Snowflake cid = m.getChannel().block().getId(); + + if (allChannelsCultable || cultableChannelIDs.contains(cid)) { + + Guild g = m.getGuild().block(); + GuildProfile gp = guildemojimaps.get(g); + if (gp == null) { + log.log(Level.INFO, "Message from unregistered guild, " + "not registering now."); + // register guild? + return Mono.empty(); + } + + if (c.equalsIgnoreCase(magicPhrase)) { + invokeDeity(g, m); + } else if (c.startsWith(magicPhrase)) { + return dispatchCommand(t, m, c); + } + } + return Mono.empty(); + }; + + Function> directmessagehandler = (var t) -> { + // System.out.println("ya boi"); + Message m = t.getMessage(); + String c = m.getContent(); + log.log(Level.FINE, "processing direct message {0}", c); + + log.log(Level.FINE, "User snowflake for message {0} is {1}", + new Object[] { c, m.getAuthor().get().getId().asString() }); + + if (c.equalsIgnoreCase(magicPhrase)) { + // System.out.println("approved"); + m.addReaction(ReactionEmoji.codepoints(randomApprovingEmoji())).subscribe(); + } else if (c.startsWith(magicPhrase)) { + return dispatchCommand(t, m, c); + } + return Mono.empty(); + }; + + private static final String alphabet = "abcdefghijklmnopqrstuvwxyz"; + + private String randomLetter() { + return "" + alphabet.charAt((int) (Math.random() * alphabet.length())); + } + + private HashMap flywheel = new HashMap<>(); + + private void start() { + if (debug_level != default_debug_level) { + log.log(Level.INFO, String.format("Starting Priestess with debug level {0}", debug_level)); + } else { + log.log(Level.INFO, String.format("Starting Priestess normally")); + } + setup(); + if (botToken.isBlank()) { + log.log(Level.SEVERE, "bot token is null. aborting."); + return; + } + dc = DiscordClientBuilder.create(botToken).build().login().block(); + if (dc == null) { + log.log(Level.SEVERE, "gatewaydiscordclient was null. aborting."); + return; + } + String boot_time = ""; + Date d = new Date(); + SimpleDateFormat df = new SimpleDateFormat("dd MMM YYYY kk:mm"); + boot_time = df.format(d); + dc.updatePresence(ClientPresence.of(Status.ONLINE, ClientActivity.playing("since " + boot_time))).subscribe(); + dc.getGuilds().flatMap((g) -> { + if (!guildemojimaps.containsKey(g)) { + guildemojimaps.put(g, new GuildProfile(g)); + } + + if (!guildnames.containsKey(g.getName())) { + guildnames.put(g.getName(), g); + } + return Mono.empty(); + }).subscribe(); + + dc.getGuilds().flatMap((g) -> g.getChannels().flatMap((channel) -> { + + log.log(Level.INFO, "Checking cultability of channel {0}", channel.getName()); + if (channel.getName().equals(cultChannelName)) { + log.log(Level.INFO, "Channel " + channel.getName() + " in " + g.getName() + " is cultable"); + cultableChannelIDs.add(channel.getId()); + } + return Mono.empty(); + })).subscribe(); + + dc.getGuilds().flatMap(g -> g.getEmojis()).flatMap(g2 -> { + // system.out.println("emoji"); + registerEmoji(g2.getGuild().block(), g2.getId(), g2.getName()); + return Mono.empty(); + }).subscribe(); + + dc.on(ConnectEvent.class, event -> { + + log.log(Level.INFO, "connected"); + + return Mono.empty(); + }).subscribe(); + + dc.on(ChatInputInteractionEvent.class).flatMap(event -> { + return event.reply().withContent("agreed"); + }).subscribe(); + + SysInListener sil = new SysInListener(); + Thread t = new Thread(sil); + + t.start(); + flywheel.put("System.in listener", t); + + dc.on(MessageCreateEvent.class).filter(event -> !event.getMessage().getAuthor().get().isBot()) + .filter(g -> !g.getGuild().blockOptional().isEmpty()).flatMap(guildedmessagehandler).subscribe(); + + dc.on(MessageCreateEvent.class).filter(event -> !event.getMessage().getAuthor().get().isBot()) + .filter(g -> g.getGuild().blockOptional().isEmpty()).flatMap(directmessagehandler).blockLast(); + } + + private int invocationsBeforeThisSession = 0; + + private void setup() { + Configuration.findConfigurationFilePath(); + Configuration.getConfigurationFromFile(); + + botToken = Configuration.getConfigurationParameter(TOKEN_KEY); + + String previousInvocations = Configuration.getConfigurationParameter(INVOCATIONS_KEY); + try { + if (previousInvocations.isBlank()) { + previousInvocations = "0"; + } + invocationsBeforeThisSession = Integer.parseInt(previousInvocations); + } catch (NumberFormatException nfe) { + System.err.println("Error reading invocations from last boot."); + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, nfe.getMessage()); + System.out.println("Invocations this boot: " + invocationsThisSession); + System.out.println("Invocation count from configuration file: " + previousInvocations); + } + + user_reader = new BufferedReader(new InputStreamReader(System.in)); + + setupWhiteList(); + + ms = setupMessageStore(); + + long free0 = Runtime.getRuntime().freeMemory(); + log.log(Level.FINE, + "Initialization complete. approx. {0} bytes free in memory.\n Attempting garbage collection.", free0); + Runtime.getRuntime().gc(); + long free1 = Runtime.getRuntime().freeMemory(); + long freediff = free1 - free0; + log.log(Level.FINE, "Post-initialization garbage collection freed ", freediff); + registerDefaultCommands(); + } + + boolean replcontinue = true; + + public static final String TOKEN_KEY = "token"; + public static final String INVOCATIONS_KEY = "invocations"; + + private void shutdown() { + replcontinue = false; + dc.logout().subscribe(); + System.out.println("Logged out"); + try { + user_reader.close(); + } catch (IOException ex) { + Logger.getLogger(Priestess.class.getName()).log(Level.SEVERE, null, ex); + } + for (Thread t : flywheel.values()) { + t.interrupt(); + } + + int invocationsTotal = invocationsBeforeThisSession + invocationsThisSession; + System.out.println("Bean Goose has been invoked " + invocationsTotal + " times so far."); + Configuration.setConfigurationParameter(INVOCATIONS_KEY, Integer.toString(invocationsTotal)); + Configuration.commitConfigurationToFile(); + System.out.println("Configuration committed to file."); + } + + private void invokeDeity(Guild g, Message m) { + int ae_custom = guildemojimaps.get(g).approvingEmojiCount(); + int emojicount = approvingEmojis.length + ae_custom; + // System.out.println(approvingEmojis.length + " default, " + ae_custom + " + // custom approving emojis."); + int which = (int) (Math.random() * emojicount); + if (which < approvingEmojis.length) { + m.addReaction(ReactionEmoji.codepoints(randomApprovingEmoji())).subscribe(); + } else { + which -= approvingEmojis.length; + m.addReaction(ReactionEmoji.custom(guildemojimaps.get(g).getEmojiByNumber(which))).subscribe(); + } + invocationsThisSession++; + + dispatchMilestone(invocationsThisSession + invocationsBeforeThisSession, g, m); + + } + + private HashMap rolewhitelist = new HashMap<>(); + + private int resolveAuthorPermissionLevel(MessageCreateEvent t, Message m) { + int level = 0; + Optional gio = t.getGuildId(); + if (gio.isPresent()) { + Member a = m.getAuthorAsMember().block(); + for (Snowflake snowflake : (Snowflake[]) a.getRoleIds().toArray(new Snowflake[3])) { + if (rolewhitelist.containsKey(snowflake)) { + int candy = rolewhitelist.get(snowflake).intValue(); + if (candy > level) { + level = candy; + } + } + } + } + + User a = m.getAuthor().get(); + Snowflake aid = a.getId(); + if (rolewhitelist.containsKey(aid)) { + int candy = rolewhitelist.get(aid).intValue(); + if (candy > level) { + level = candy; + } + } + + if (fromCatluck(m)) { + level = MAX_PERMS; + } + return level; + } + + private boolean fromCatluck(Message m) { + String s = Configuration.getConfigurationParameter(CATLIST); + Optional ao = m.getAuthor(); + if (ao.isPresent()) { + for (String s1 : s.split(" ")) { + if (s1.equals(ao.get().getId().asString())) { + System.out.println("Literally catluck detected."); + return true; + } + } + } + return false; + } + + private void dispatchMilestone(int i, Guild g, Message m) { + if ((i % 5) == 0) { + MessageCreateSpec mcs = MessageCreateSpec.create().withMessageReference(m.getId()) + .withContent(randomMessage()); + m.getChannel().block().createMessage(mcs).subscribe(); + } + } + + private ArrayList messages = new ArrayList<>(); + + private String randomMessage() { + if (ms.messagesAvailable()) { + return ms.randomMessage(); + } + if (messages.isEmpty()) { + return "bean goose approves"; + } + return messages.get((int) (Math.random() * messages.size())); + } + + private void setupWhiteList() { + String rolelist = Configuration.getConfigurationParameter(WHITELIST); + if (!rolelist.isBlank()) { + + String subtokenDelimiter = "/"; + + String[] tokens = rolelist.split(" "); + for (String token : tokens) { + + String sflake = token.substring(0, token.indexOf(subtokenDelimiter)); + String perm = token.substring(token.indexOf(subtokenDelimiter) + subtokenDelimiter.length(), + token.length()); + + System.out.println( + "Adding snowflake (" + sflake + ") to whitelist with permission level (" + perm + ")."); + + Snowflake a = Snowflake.of(sflake); + + rolewhitelist.put(a, Integer.parseInt(perm)); + } + } + } + + /* + * + */ + private MessageStore setupMessageStore() { + String mesglist = Configuration.getConfigurationParameter(MESSAGES); + File f = Paths.get(mesglist).toFile(); + try { + MessageStore ms1 = new MessageStore(f); + return ms1; + } catch (IOException e) { + if (!f.exists()) { + log.log(Level.WARNING, "Message store file does not exist."); + } else { + log.log(Level.SEVERE, e.getMessage()); + } + } + return null; + } + + private void reloadMessageStore() { + MessageStore ms1 = setupMessageStore(); + ms1.waitUntilLoaded(); + ms = ms1; + } + + private Guild resolveGuildByNameOrId(String token) { + log.log(Level.INFO, "Finding guild by name or ID " + token); + if (guildnames.containsKey(token)) { + return guildnames.get(token); + } + return this.dc.getGuildById(Snowflake.of(token)).block(); + } + + private class SysInListener implements Runnable { + + @Override + public void run() { + try { + while (replcontinue) { + while (!user_reader.ready()) { + Thread.sleep(1000); + if (!replcontinue) { + user_reader.close(); + return; + } + } + String a = user_reader.readLine(); + dispatchCommand(null, null, a, LOCAL_PERMS); + } + user_reader.close(); + } catch (IOException ex) { + Logger.getLogger(Priestess.class.getName()).log(Level.SEVERE, null, ex); + } catch (InterruptedException ex) { + Logger.getLogger(this.getClass().getName()).log(Level.INFO, "System.in Listener interrupted."); + } + System.out.println("break repl"); + } + + } + + private static void tryPush(ArrayList a, StringBuilder s) { + if (!s.isEmpty()) { + a.add(s.toString()); + } + } + + public static String[] tokenize(String payload) { + ArrayList a = new ArrayList<>(); + StringBuilder s = new StringBuilder(); + boolean inQuote = false; + for (char c : payload.toCharArray()) { + // log.log(Level.FINE, String.format("c: %c, inQuote: %s", c, (inQuote ? "yes" : + // "no"))); + if (!inQuote && c == '\"') { + inQuote = true; + tryPush(a, s); + s.delete(0, s.length()); + } else if (inQuote && c == '\"') { + inQuote = false; + tryPush(a, s); + s.delete(0, s.length()); + } else if (!inQuote && c == ' ') { + tryPush(a, s); + s.delete(0, s.length()); + } else { + s.append(c); + } + } + tryPush(a, s); + if (inQuote) { + log.log(Level.WARNING, "Unterminated quote passed to tokenizer"); + return null; + } + return a.toArray(new String[a.size()]); + } + + /** + * I wanted the replacement string to be {xxxx} without the dollar sign, but + * unit tests failed when the help/usage was nothing but {xxxx}. Instead of + * investigating, I gave up and added a dollar sign to make it something like + * Python's f-strings. Or JS' backtick-strings, I can never remember which is + * which. + */ + public static class Callback implements Function> { + + final Logger log = Logger.getLogger(Callback.class.getName()); + String[] usages = { "Undefined command usage" }; + String help = "${usage}"; + + @Override + public Publisher apply(CommandArgs t) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from + // nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + public String getHelp(String commandName) { + String s = getUsage(commandName); + return help/* .replaceAll("\\$\\{usage\\}", s) */.replaceAll("\\$\\{commandname\\}", commandName); + } + + public String getUsage(String commandName) { + StringBuilder u = new StringBuilder(); + for (int i = 0; i < usages.length; i++) { + String s = usages[i]; + s.replaceAll("\\$\\{commandname\\}", commandName); + u.append(s); + if (i != usages.length - 1) { + u.append(NEWLINE); + } + } + return u.toString(); + } + + } + + public final Callback registerEmojiCommand = new Callback() { + + String usage = "{commandname} EMOJI"; + String help = "register emoji for use in basic invocations." + "" + "" + "" + ""; + + @Override + public Publisher apply(CommandArgs o) { + String[] tokens = tokenize(o.getPayload()); + String emojiname = tokens[0]; + + Guild g; + if (tokens.length == 3 && "in".equals(tokens[1])) { + g = resolveGuildByNameOrId(tokens[2]); + } else { + if (o.getMessage() != null) { + g = o.getMessage().getGuild().block(); + } else { + o.replyWith("Could not determine what guild to register emoji with."); + return null; + } + } + + Snowflake s = (Snowflake) guildemojimaps.get(g).getCustomemojis().get(emojiname); + + if (s != null) { + + GuildEmoji emoji = g.getGuildEmojiById(s).block(); + o.getMessage().addReaction(ReactionEmoji.custom(emoji)).subscribe(); + guildemojimaps.get(o.getMessage().getGuild().block()).setApprovingEmoji(emoji.getName(), emoji.getId()); + } else { + log.log(Level.WARNING, "tried registering emoji ''{0}'' but no dice", emojiname); + } + return null; + } + }; + + public final Callback commitConfigurationCommand = new Callback() { + @Override + public Publisher apply(CommandArgs o) { + System.out.println("Committing configuration to file."); + Configuration.commitConfigurationToFile(); + return Mono.empty(); + } + }; + + /** + * Show system status + */ + public final Callback showCommand = new Callback() { + @Override + public Publisher apply(CommandArgs o) { + System.out.println("System Status:"); + guildemojimaps.forEach((guild, gp) -> { + System.out.println("\n" + guild.getName() + ":"); + gp.getCustomemojis().forEach((name, snow) -> { + System.out.println("\n\t" + name + ": " + snow.asString()); + }); + }); + log.log(Level.INFO, "Configuration file location is " + Configuration.getCONFIG_FILE_LOCATION()); + return Mono.empty(); + } + }; + + public final Callback setConfigCommand = new Callback() { + @Override + public Publisher apply(CommandArgs o) { + String pay2 = cdr("set", o.getPayload()); + String[] paytokens = tokenize(pay2); + if (paytokens.length == 2) { + log.log(Level.INFO, "setting configuration parameter " + paytokens[0] + " to " + paytokens[1]); + Configuration.setConfigurationParameter(paytokens[0], paytokens[1]); + } else { + log.log(Level.INFO, "Invalid argument count for set configuration parameter command"); + } + return Mono.empty(); + } + }; + + public final Callback showConfigCommand = new Callback() { + @Override + public Publisher apply(CommandArgs o) { + log.log(Level.INFO, "Showing configuration."); + log.log(Level.INFO, Configuration.enumerateConfiguration()); + return Mono.empty(); + } + }; + + public final Callback permissionLevelCommand = new Callback() { + @Override + public Publisher apply(CommandArgs o) { + o.replyWith(String.format("Your permission level in this context is %s", o.getPermCalledWith())); + return Mono.empty(); + } + }; + + public final Callback setCultableChannelsCommand = new Callback() { + @Override + public Publisher apply(CommandArgs o) { + String p = o.getPayload(); + if (p.isBlank()) { + o.replyWith("Culting all channels"); + allChannelsCultable = true; + } else { + String[] tokens = tokenize(p); + if (isAffirmative(tokens[0])) { + o.replyWith("Culting all channels"); + allChannelsCultable = true; + } else if (isNegatory(tokens[0])) { + o.replyWith("Removing all-channel cult"); + allChannelsCultable = false; + } else if (tokens.length >= 2) { + Guild g = resolveGuildByNameOrId(tokens[0]); + if (g != null) { + GuildChannel c = g.getChannels().filter(new Predicate() { + @Override + public boolean test(GuildChannel t) { + return t.getName().equals(tokens[1]); + } + }).blockFirst(); + if (c != null) { + if (tokens.length == 3) { + if (isAffirmative(tokens[2])) { + cultableChannelIDs.add(c.getId()); + o.replyWith("Adding channel to cultable channels list"); + } else if (isNegatory(tokens[2])) { + o.replyWith("Removing channel from cultable channels list"); + cultableChannelIDs.remove(c); + } else { + o.replyWith("Could not determine whether to cult or uncult channel."); + } + } + } else { + o.replyWith("Could not resolve channel to cult or uncult."); + } + } + } else { + o.replyWith("Unknown parameters for command"); + } + } + return Mono.empty(); + } + + private boolean isAffirmative(String token) { + return "yes".equalsIgnoreCase(token); + } + + private boolean isNegatory(String token) { + return "no".equalsIgnoreCase(token); + } + }; + + public final Callback shutdownCommand = new Callback() { + @Override + public Publisher apply(CommandArgs o) { + log.log(Level.INFO, "Shutting down."); + shutdown(); + return Mono.empty(); + } + }; + + public final Callback l = new Callback() { + @Override + public Publisher apply(CommandArgs o) { + + String[] arglist = o.getPayload().split(" "); + if (arglist.length != 2) { + + return Mono.empty(); + } + Snowflake s = Snowflake.of(arglist[0]); + return Mono.empty(); + } + }; + + public final Callback sendToCommand = new Callback() { + @Override + public Publisher apply(CommandArgs o) { + + String[] arglist = o.getPayload().split(" "); + if (arglist.length < 3) { + o.replyWith("Not enough arguments."); + return Mono.empty(); + } + Guild a = resolveGuildByNameOrId(arglist[0]); + // guildnames.get(arglist[0]); + /* + * for (Object a0 : guildnames.entrySet().toArray()) { Map.Entry + * a3 = (Map.Entry) a0; Guild a1 = (Guild) a3.getValue(); if + * (a1.getId().asString().equals(arglist[0])) { a = a1; } } + */ + + if (a == null) { + o.replyWith("Could not find guild"); + return Mono.empty(); + } + a.getChannels().flatMap((ch) -> { + if (ch.getName().equals(arglist[1])) { + String argrest = ""; + for (int i = 2; i < arglist.length; i++) { + argrest += arglist[i] + " "; + } + argrest = argrest.substring(0, argrest.length() - 1); + TextChannel ch2 = (TextChannel) ch; + MessageCreateSpec mcs = MessageCreateSpec.create().withContent(argrest); + ch2.createMessage(mcs).subscribe(); + } + return Mono.empty(); + }).blockLast(); + return Mono.empty(); + } + }; + + public final Callback reloadMessageStoreCommand = new Callback() { + @Override + public Publisher apply(CommandArgs o) { + log.log(Level.INFO, "Attempting to reload messages."); + reloadMessageStore(); + log.log(Level.INFO, "Messages reloaded, {0} in registry.", ms.messageCount()); + return Mono.empty(); + } + }; + + private void registerDefaultCommands() { + Command.registerCommand(new Command("status", 1).setCallback(showCommand)); + Command.registerCommand(new Command("reload messages", 1).setCallback(reloadMessageStoreCommand)); + Command.registerCommand(new Command("use emoji", 1).setCallback(registerEmojiCommand)); + Command.registerCommand(new Command("show config", 1).setCallback(showConfigCommand)); + Command.registerCommand(new Command("set", 1).setCallback(setConfigCommand)); + Command.registerCommand(new Command("shutdown", 50).setCallback(shutdownCommand)); + Command.registerCommand(new Command("send to", 1).setCallback(sendToCommand)); + Command.registerCommand(new Command("cult", 9000).setCallback(setCultableChannelsCommand)); + Command.registerCommand(new Command("perm", 0).setCallback(permissionLevelCommand)); + Command.registerCommand( + Command.commandThatJustRepliesWith("is minecraft online", "i dunno log on and find out smfh")); + + } } diff --git a/src/main/java/com/tinyplantnews/priestess/WordsAndWhatTheyMean.java b/src/main/java/com/tinyplantnews/priestess/WordsAndWhatTheyMean.java index c86e3ea..706e127 100644 --- a/src/main/java/com/tinyplantnews/priestess/WordsAndWhatTheyMean.java +++ b/src/main/java/com/tinyplantnews/priestess/WordsAndWhatTheyMean.java @@ -9,5 +9,5 @@ package com.tinyplantnews.priestess; * @author atomb */ public class WordsAndWhatTheyMean { - + } diff --git a/src/test/java/com/tinyplantnews/priestess/PriestessTest.java b/src/test/java/com/tinyplantnews/priestess/PriestessTest.java index 6ce7686..42a2d1a 100644 --- a/src/test/java/com/tinyplantnews/priestess/PriestessTest.java +++ b/src/test/java/com/tinyplantnews/priestess/PriestessTest.java @@ -17,101 +17,87 @@ import org.junit.jupiter.params.ParameterizedTest; */ public class PriestessTest { - public PriestessTest() { - } + public PriestessTest() { + } - @org.junit.jupiter.api.BeforeAll - public static void setUpClass() throws Exception { - } + @org.junit.jupiter.api.BeforeAll + public static void setUpClass() throws Exception { + } - @org.junit.jupiter.api.AfterAll - public static void tearDownClass() throws Exception { - } + @org.junit.jupiter.api.AfterAll + public static void tearDownClass() throws Exception { + } - /** - * Test of main method, of class Priestess. - */ - @org.junit.jupiter.api.Test - public void testMain() { - System.out.println("main"); - String[] args = {"testsuite"}; - Priestess.main(args); - } + /** + * Test of main method, of class Priestess. + */ + @org.junit.jupiter.api.Test + public void testMain() { + System.out.println("main"); + String[] args = { "testsuite" }; + Priestess.main(args); + } - - @org.junit.jupiter.api.Test - public void testCallbackHelpTexts(){ - assertEquals("boi", "son".replaceAll("son", "boi")); - - - Priestess p = new Priestess(); - p.shutdownCommand.help = "ha boi"; - testCallbackHelpText(p.shutdownCommand, - "shut down", - "ha boi"); - - p.shutdownCommand.help = "${commandname}"; - testCallbackHelpText(p.shutdownCommand, - "shut down", - "shut down"); - - p.shutdownCommand.help = "${commandname} turns off the entire internet"; - testCallbackHelpText(p.shutdownCommand, - "shut down", - "shut down turns off the entire internet"); - } - - private void testCallbackHelpText(Priestess.Callback c, String name, String expHelp){ - String help = c.getHelp(name); - Assertions.assertEquals(expHelp, help); - } - - /** - * Test of tokenize method, of class Priestess. - */ - @Test - public void testTokenize() { - testTokenize1("a", - new String[]{"a"}); - testTokenize1("a, b", - new String[]{"a,", "b"}); - testTokenize1("ya boi", - new String[]{"ya", "boi"}); - //Should handle these trivially. Single quotes not special. - testTokenize1("'''' ''' ' '''", - new String[]{"''''", "'''", "'", "'''"}); - testTokenize1("*^@^$/><::;''", - new String[]{"*^@^$/><::;''"}); - testTokenize1("*^@^$/> <::;''", - new String[]{"*^@^$/>", "<::;''"}); - testTokenize1("this is not quoted, \"this is\"", - new String[]{"this", "is", "not", "quoted,", "this is"}); - testTokenize1("this is not quoted, \"this is", - null); - /*testTokenize1("this is not quoted, \\\"this is", - new String[]{"this", "is", "not", "quoted,", "\"this is"});*/ - } + @org.junit.jupiter.api.Test + public void testCallbackHelpTexts() { + assertEquals("boi", "son".replaceAll("son", "boi")); - private void testTokenize1(String payload, String[] expResult) { - System.out.println("tokenize for payload " + payload); - String[] result = Priestess.tokenize(payload); - if (expResult == null && result == null) { - return; - } else if (result == null && expResult != null) { - fail("Tokenize() returned null array"); - } - for (int i = 0; i < Math.max(expResult.length, result.length); i++) { - String a = ""; - String b = ""; - if (expResult.length > i) { - a = expResult[i]; - } - if (result.length > i) { - b = result[i]; - } - System.out.println(String.format("\te: %s r: %s", a, b)); - } - assertArrayEquals(expResult, result); - } + Priestess p = new Priestess(); + p.shutdownCommand.help = "ha boi"; + testCallbackHelpText(p.shutdownCommand, "shut down", "ha boi"); + + p.shutdownCommand.help = "${commandname}"; + testCallbackHelpText(p.shutdownCommand, "shut down", "shut down"); + + p.shutdownCommand.help = "${commandname} turns off the entire internet"; + testCallbackHelpText(p.shutdownCommand, "shut down", "shut down turns off the entire internet"); + } + + private void testCallbackHelpText(Priestess.Callback c, String name, String expHelp) { + String help = c.getHelp(name); + Assertions.assertEquals(expHelp, help); + } + + /** + * Test of tokenize method, of class Priestess. + */ + @Test + public void testTokenize() { + testTokenize1("a", new String[] { "a" }); + testTokenize1("a, b", new String[] { "a,", "b" }); + testTokenize1("ya boi", new String[] { "ya", "boi" }); + // Should handle these trivially. Single quotes not special. + testTokenize1("'''' ''' ' '''", new String[] { "''''", "'''", "'", "'''" }); + testTokenize1("*^@^$/><::;''", new String[] { "*^@^$/><::;''" }); + testTokenize1("*^@^$/> <::;''", new String[] { "*^@^$/>", "<::;''" }); + testTokenize1("this is not quoted, \"this is\"", new String[] { "this", "is", "not", "quoted,", "this is" }); + testTokenize1("this is not quoted, \"this is", null); + /* + * testTokenize1("this is not quoted, \\\"this is", new String[]{"this", "is", + * "not", "quoted,", "\"this is"}); + */ + } + + private void testTokenize1(String payload, String[] expResult) { + System.out.println("tokenize for payload " + payload); + String[] result = Priestess.tokenize(payload); + if (expResult == null && result == null) { + return; + } else if (result == null && expResult != null) { + fail("Tokenize() returned null array"); + } + for (int i = 0; i < Math.max(expResult.length, result.length); i++) { + String a = ""; + String b = ""; + if (expResult.length > i) { + a = expResult[i]; + } + if (result.length > i) { + b = result[i]; + } + System.out.println(String.format("\te: %s r: %s", a, b)); + } + assertArrayEquals(expResult, result); + } }