calculator bot implemented

pull/2/head
Vyacheslav N. Boyko 2017-11-15 17:49:03 +03:00
parent 87d16a1fe4
commit 340a9296c7
6 changed files with 380 additions and 0 deletions

21
MainApp.java 100644
View File

@ -0,0 +1,21 @@
package ru.bvn13.jircbot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import ru.bvn13.jircbot.bot.JircBot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@ComponentScan("ru.bvn13.jircbot")
public class MainApp {
@Autowired
private JircBot bot;
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
System.out.println("==============> STARTING <==============");
}
}

80
bot/JircBot.java 100644
View File

@ -0,0 +1,80 @@
package ru.bvn13.jircbot.bot;
import org.pircbotx.Configuration;
import org.pircbotx.PircBotX;
import org.pircbotx.UtilSSLSocketFactory;
import org.pircbotx.cap.TLSCapHandler;
import org.pircbotx.hooks.ListenerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import ru.bvn13.jircbot.config.JircBotConfiguration;
import ru.bvn13.jircbot.listeners.CalculatorListener;
import ru.bvn13.jircbot.listeners.TestListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class JircBot extends ListenerAdapter {
private static Logger logger = LoggerFactory.getLogger(JircBot.class);
private JircBotConfiguration config;
private Map<String, PircBotX> bots = new HashMap<>();
@Autowired
public JircBot(JircBotConfiguration config) {
this.config = config;
this.start();
}
public void start() {
//Setup this bot
Configuration.Builder templateConfig = new Configuration.Builder()
.setLogin("JIrcBot") //login part of hostmask, eg name:login@host
.setAutoNickChange(true) //Automatically change nick when the current one is in use
.setCapEnabled(true) //Enable CAP features
.addCapHandler(new TLSCapHandler(new UtilSSLSocketFactory().trustAllCertificates(), true));
this.config.getConnections().forEach(c -> {
List<Configuration.ServerEntry> servers = new ArrayList<>();
servers.add(new Configuration.ServerEntry(c.getServer(), c.getPort()));
this.bots.put(
String.format("%s/%s", c.getServer(), c.getChannelName()),
new PircBotX(templateConfig
.setName(c.getBotName())
.addListener(new CalculatorListener()) //This class is a listener, so add it to the bots known listeners
.setServers(servers)
.setAutoReconnect(true)
.addAutoJoinChannel(c.getChannelName()) //Join the official #pircbotx channel
.buildForServer(c.getServer())
)
);
});
//bot.connect throws various exceptions for failures
this.bots.forEach((id, b) -> {
try {
b.startBot();
} catch (Exception ex) {
logger.error("ERROR STARTING BOT: "+id);
ex.printStackTrace();
}
});
}
}

View File

@ -0,0 +1,81 @@
package ru.bvn13.jircbot.config;
import lombok.Getter;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import ru.bvn13.jircbot.model.Config;
import javax.annotation.PostConstruct;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@Configuration
public class JircBotConfiguration {
private static Logger logger = LoggerFactory.getLogger(JircBotConfiguration.class);
@Value("${config}")
private String configFileName;
@Getter
private List<Config> connections = new ArrayList<>();
@PostConstruct
public void readConfigFile() {
logger.debug("Start reading configuration file: "+this.configFileName);
JSONParser parser = new JSONParser();
Reader reader = null;
try {
reader = new FileReader(this.configFileName);
Object jsonObj = parser.parse(reader);
JSONObject jsonObject = (JSONObject) jsonObj;
logger.debug("CONFIG VERSION: "+jsonObject.get("version"));
JSONArray settings = (JSONArray) jsonObject.get("connections");
Iterator<JSONObject> iterator = settings.iterator();
while (iterator.hasNext()) {
Config config = this.parseConfig(iterator.next());
if (config.getEnabled())
this.connections.add(config);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new InternalError("Config file not found: "+this.configFileName);
} catch (ParseException e) {
e.printStackTrace();
throw new InternalError("Wrong config file format. JSON is expected.");
} catch (IOException e) {
e.printStackTrace();
throw new InternalError("Config is not readable.");
}
}
private Config parseConfig(JSONObject data) {
Config config = new Config();
config.setEnabled((Boolean)data.get("enabled"));
config.setServer((String)data.get("server"));
config.setPort(Integer.parseInt(data.get("port").toString()));
config.setChannelName((String)data.get("channelName"));
config.setBotName((String)data.get("botName"));
return config;
}
}

View File

@ -0,0 +1,109 @@
package ru.bvn13.jircbot.listeners;
import net.objecthunter.exp4j.Expression;
import net.objecthunter.exp4j.ExpressionBuilder;
import org.pircbotx.hooks.ListenerAdapter;
import org.pircbotx.hooks.WaitForQueue;
import org.pircbotx.hooks.events.MessageEvent;
import org.pircbotx.hooks.types.GenericMessageEvent;
public class CalculatorListener extends ListenerAdapter {
private static final String COMMAND = "?calc";
@Override
public void onGenericMessage(final GenericMessageEvent event) throws Exception {
if (event.getUser().getNick().equals(event.getBot().getNick())) {
return;
}
if (!event.getMessage().startsWith(COMMAND)) {
return;
}
String message = event.getMessage().replace(COMMAND, "").trim();
String[] commands = message.split(" ", 2);
if (commands.length == 0 || commands[0].isEmpty() || commands[0].trim().equalsIgnoreCase("help")) {
event.respond(this.helpMessage());
return;
}
if (this.checkComand(commands[0].trim())) {
return;
}
String expressionString = message;
event.respond("EXPRESSION: "+expressionString);
ExpressionBuilder expressionBuilder = new ExpressionBuilder(expressionString);
Expression exp = null;
WaitForQueue queue = new WaitForQueue(event.getBot());
while (true) {
MessageEvent currentEvent = queue.waitFor(MessageEvent.class);
if (currentEvent.getMessage().startsWith(COMMAND)) {
message = currentEvent.getMessage().replace(COMMAND, "").trim();
commands = message.split(" ", 2);
if (commands.length == 0 || commands[0].isEmpty()) {
currentEvent.respond("Command is expected.");
currentEvent.respond(this.helpMessage());
} else if (commands[0].trim().equalsIgnoreCase("vars")) {
exp = expressionBuilder.variables(commands[1].trim()).build();
currentEvent.respond("VARIABLES: "+commands[1].trim());
} else if (commands[0].trim().equalsIgnoreCase("set")) {
String[] variableData = commands[1].trim().split("=", 2);
if (variableData.length < 2 || variableData[0].isEmpty() || variableData[1].isEmpty()) {
currentEvent.respond("FORMAT: variable = value");
} else {
if (exp == null) {
//currentEvent.respond("Variables are not set!");
exp = expressionBuilder.build();
} else {
Double value = Double.parseDouble(variableData[1].trim());
exp = exp.setVariable(variableData[0].trim(), value);
currentEvent.respond(String.format("VARIABLE SET: %s = %f", variableData[0].trim(), value));
}
}
} else if (commands[0].trim().equalsIgnoreCase("done")) {
if (exp == null) {
exp = expressionBuilder.build();
}
Double result = exp.evaluate();
currentEvent.respond(String.format("%s = %f", expressionString, result));
expressionBuilder = null;
exp = null;
queue.close();
return;
} else {
currentEvent.respond(this.helpMessage());
}
} else {
currentEvent.respond("Command must be started with: "+COMMAND);
}
}
}
private Boolean checkComand(String command) {
return command.equalsIgnoreCase("vars")
|| command.equalsIgnoreCase("set")
|| command.equalsIgnoreCase("done");
}
private String helpMessage() {
return "CALCULATOR (powered by Exp4J) | "+
"Commands: | "+
"vars - set variables names delimetered by comma, i.e.: a, b | "+
"set - set variable, i.e.: a = 2 | "+
"done - evaluate expression";
}
}

View File

@ -0,0 +1,66 @@
package ru.bvn13.jircbot.listeners;
import org.pircbotx.dcc.ReceiveChat;
import org.pircbotx.hooks.ListenerAdapter;
import org.pircbotx.hooks.WaitForQueue;
import org.pircbotx.hooks.events.IncomingChatRequestEvent;
import org.pircbotx.hooks.events.MessageEvent;
import org.pircbotx.hooks.types.GenericMessageEvent;
public class TestListener extends ListenerAdapter {
@Override
public void onGenericMessage(final GenericMessageEvent event) throws Exception {
//Hello world
//This way to handle commands is useful for listeners that listen for multiple commands
if (event.getMessage().startsWith("?hello"))
event.respond("Hello World!");
//If this isn't a waittest, ignore
//This way to handle commands is useful for listers that only listen for one command
if (!event.getMessage().startsWith("?waitTest start"))
return;
//WaitTest has started
event.respond("Started...");
WaitForQueue queue = new WaitForQueue(event.getBot());
//Infinate loop since we might recieve messages that aren't WaitTest's.
while (true) {
//Use the waitFor() method to wait for a MessageEvent.
//This will block (wait) until a message event comes in, ignoring
//everything else
MessageEvent currentEvent = queue.waitFor(MessageEvent.class);
//Check if this message is the "ping" command
if (currentEvent.getMessage().startsWith("?waitTest ping"))
event.respond("pong");
//Check if this message is the "end" command
else if (currentEvent.getMessage().startsWith("?waitTest end")) {
event.respond("Stopping");
queue.close();
//Very important that we end the infinate loop or else the test
//will continue forever!
return;
}
}
}
@Override
public void onIncomingChatRequest(IncomingChatRequestEvent event) throws Exception {
//Accept the incoming chat request. If it fails it will throw an exception
ReceiveChat chat = event.accept();
//Read lines from the server
String line;
while ((line = chat.readLine()) != null)
if (line.equalsIgnoreCase("done")) {
//Shut down the chat
chat.close();
break;
} else {
//Fun example
int lineLength = line.length();
chat.sendLine("Line '" + line + "' contains " + lineLength + " characters");
}
}
}

23
model/Config.java 100644
View File

@ -0,0 +1,23 @@
package ru.bvn13.jircbot.model;
import com.sun.istack.internal.NotNull;
import lombok.Data;
@Data
public class Config {
@NotNull
private Boolean enabled = false;
@NotNull
private String server;
@NotNull
private Integer port = 6667;
@NotNull
private String botName;
private String channelName;
}