From f2eec77df09a203849ea01dc4f12d24bad2bf283 Mon Sep 17 00:00:00 2001 From: Sandy Mossgrave Date: Sun, 7 May 2023 19:56:57 +0000 Subject: [PATCH] General fixes. Works. Formatted source files. Fixed command-line arguments processing. Added ability to specify logging levels by name (ALL, FINE, FINER...) Generally fixed unnoticed problems in Configuration and Priestess classes. Stopped spuriously committing configuration file path to preferences store, changed some Priestess methods to use her own tokenizer, and fixed a null check in setCultableChannels method. --- .gitignore | 1 + .../com/tinyplantnews/priestess/Command.java | 199 +- .../tinyplantnews/priestess/CommandArgs.java | 62 +- .../priestess/CommandStatus.java | 5 +- .../priestess/Configuration.java | 302 +-- .../priestess/CustomLoggingLevel.java | 6 +- .../tinyplantnews/priestess/GuildProfile.java | 91 +- .../priestess/InstantiableConfiguration.java | 262 +-- .../tinyplantnews/priestess/JKRSONTag.java | 67 +- .../tinyplantnews/priestess/JKRowlingSON.java | 32 +- .../tinyplantnews/priestess/MessageStore.java | 201 +- .../tinyplantnews/priestess/Priestess.java | 1614 ++++++++--------- .../priestess/WordsAndWhatTheyMean.java | 2 +- .../priestess/PriestessTest.java | 168 +- 14 files changed, 1508 insertions(+), 1504 deletions(-) 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); + } }