Commands, step 1: parsing and handling.

keep-around/d31701866686f66088b78de2e29736ae36e55a68
Pingex aka Raphaël 9 years ago
parent 6d9f31f592
commit 01057f8492

@ -13,4 +13,7 @@ discord.token = tokenGoesHere
# ... or username/password combination if you don't use bot mode
# comment out discord.token if using us/pw tuple
#discord.username = email
#discord.password = superSecretPassword
#discord.password = superSecretPassword
# Command prefix
commands.prefix = !

@ -0,0 +1,48 @@
package net.pingex.dcf.commands;
import net.pingex.dcf.core.Configuration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Basic command parser.
*/
public class BasicParser implements ICommandParser
{
private Pattern commandPattern = Pattern.compile("^" + Configuration.COMMAND_PREFIX + "([:\\w]+)(?: (.*))?$");
private Pattern argsPattern = Pattern.compile("([^\"]\\S*|\".+?\")\\s*");
@Override
public boolean checkSyntax(String input)
{
return commandPattern.matcher(input).matches();
}
@Override
public String parseCommand(String input) throws ParserException
{
Matcher m = commandPattern.matcher(input);
if(!m.matches()) throw new ParserException("String cannot be parsed for a command.");
return m.group(1);
}
@Override
public List<String> parseArguments(String input) throws ParserException
{
Matcher mc = commandPattern.matcher(input);
if(!mc.matches()) throw new ParserException("String cannot be parsed for a command.");
// CASE: Command has no arg
if(mc.group(2) == null) return Collections.emptyList();
// CASE: Command has args
Matcher ma = argsPattern.matcher(mc.group(2));
List<String> argsOut = new ArrayList<>();
while(ma.find()) argsOut.add(ma.group(1).replace("\"", ""));
return argsOut;
}
}

@ -0,0 +1,45 @@
package net.pingex.dcf.commands;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import sx.blah.discord.handle.impl.events.MessageReceivedEvent;
import java.util.List;
/**
* Landing class for a MRE
*/
public class CommandHandler
{
/**
* The one and only valid parser for now.
*/
public static final ICommandParser PARSER = new BasicParser();
/**
* Logger
*/
private static final Logger LOGGER = LogManager.getLogger(CommandHandler.class);
/**
* Landing method for a MRE
*/
public static void handle(MessageReceivedEvent event)
{
String command;
List<String> arguments;
try
{
command = PARSER.parseCommand(event.getMessage().getContent());
arguments = PARSER.parseArguments(event.getMessage().getContent());
}
catch(ParserException e)
{
return; // Not a command
}
LOGGER.debug("Attempting to run command {} by user #{}.", command, event.getMessage().getAuthor().getID());
}
}

@ -0,0 +1,32 @@
package net.pingex.dcf.commands;
import java.util.List;
/**
* General interface for a command parser.
*/
public interface ICommandParser
{
/**
* Checks the syntax of a command.
* @param input Input String, ie. the message content.
* @return `true` if the string is a command, `false` otherwise.
*/
boolean checkSyntax(String input);
/**
* Gives the command part of a command string.
* @param input Input String, ie. the message content.
* @return The command part of the inputted string.
* @throws ParserException whether the inputted string cannot be parsed for a command.
*/
String parseCommand(String input) throws ParserException;
/**
* Gives the arguments list of a command string.
* @param input Input String, ie. the message content.
* @return The arguments list of the inputted string.
* @throws ParserException whether the inputted string cannot be parsed for a command.
*/
List<String> parseArguments(String input) throws ParserException;
}

@ -0,0 +1,17 @@
package net.pingex.dcf.commands;
/**
* Thrown when the parser cannot parse.
*/
public class ParserException extends Exception
{
public ParserException()
{
super();
}
public ParserException(String message)
{
super(message);
}
}

@ -0,0 +1,4 @@
/**
* Contains everything related to commands parsing and executing.
*/
package net.pingex.dcf.commands;

@ -89,6 +89,11 @@ public class Configuration
*/
public static String DATA_DIR = "data";
/**
* Command prefix string
*/
public static String COMMAND_PREFIX = "!";
/**
* Tells if the bot is configured to connect using a token or an username/password tuple.
* @return Whether the main connection is a bot, or not
@ -106,6 +111,7 @@ public class Configuration
BOT_NAME = store.getString("general.bot_name", BOT_NAME);
PLUGINS_DIR = store.getString("general.plugins_dir", PLUGINS_DIR);
DATA_DIR = store.getString("general.storage_dir", DATA_DIR);
COMMAND_PREFIX = store.getString("commands.prefix", COMMAND_PREFIX);
// Validate main connection username/password or token
if(isConnectionToken())

@ -1,5 +1,6 @@
package net.pingex.dcf.core;
import net.pingex.dcf.commands.CommandHandler;
import net.pingex.dcf.modularity.PluginWrapper;
import net.pingex.dcf.modularity.events.EventManager;
import org.apache.logging.log4j.LogManager;
@ -53,6 +54,7 @@ public class CoreEventsHandler
public static void onMessageReceived(MessageReceivedEvent event)
{
LOGGER.trace("Received message from channel #{}.", event.getMessage().getChannel().getID());
CommandHandler.handle(event);
}
@EventSubscriber
@ -92,7 +94,7 @@ public class CoreEventsHandler
public static void pluginRunning(PluginWrapper plugin)
{
EventManager.getInstance().checkAndRegister(plugin); // Hook: event handlers
// TODO: Hook: commands
// TODO: Hook: register commands (if implements appropriate interface)
}
/**
@ -102,6 +104,7 @@ public class CoreEventsHandler
public static void pluginStopped(PluginWrapper plugin)
{
EventManager.getInstance().unregister(plugin); // Hook: event handlers
// TODO: Hook: unregister commands
}
/**