diff --git a/pom.xml b/pom.xml index a0cb9c3..1ba5fea 100644 --- a/pom.xml +++ b/pom.xml @@ -19,18 +19,19 @@ 3.23.1 compile - - com.google.code.gson - gson - 2.8.5 - compile - org.mongodb mongodb-driver-sync 3.9.1 compile + + + org.ini4j + ini4j + 0.5.4 + + commons-cli commons-cli diff --git a/src/main/java/InnaIrcBot/Commanders/ChanelCommander.java b/src/main/java/InnaIrcBot/Commanders/ChanelCommander.java index 525bd4b..f32c387 100644 --- a/src/main/java/InnaIrcBot/Commanders/ChanelCommander.java +++ b/src/main/java/InnaIrcBot/Commanders/ChanelCommander.java @@ -1,41 +1,36 @@ package InnaIrcBot.Commanders; import InnaIrcBot.ProvidersConsumers.StreamProvider; +import InnaIrcBot.config.ConfigurationChannel; +import InnaIrcBot.config.ConfigurationManager; -import java.io.*; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.concurrent.BlockingQueue; import java.util.regex.Pattern; - //TODO: FLOOD, JOIN FLOOD - // TODO: @ configuration level: if in result we have empty string, no need to pass it to server + //TODO: FLOOD public class ChanelCommander implements Runnable { private final BlockingQueue streamQueue; private final String server; private final String channel; //TODO: add timers - private final HashMap joinMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw - private final HashMap msgMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw - private final HashMap nickMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw + private HashMap joinMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw + private HashMap msgMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw + private HashMap nickMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw - private boolean joinFloodTrackNeed = false; + private boolean joinFloodTrackNeed = false; private JoinFloodHandler jfh; - private boolean joinCloneTrackNeed = false; // todo:fix + private boolean joinCloneTrackNeed = false; // todo:fix private JoinCloneHandler jch; - public ChanelCommander(BlockingQueue stream, String serverName, String channel, String configFilePath){ + public ChanelCommander(BlockingQueue stream, String serverName, String channel) throws Exception{ this.streamQueue = stream; this.server = serverName; this.channel = channel; - - this.joinMap = new HashMap<>(); - this.msgMap = new HashMap<>(); - this.nickMap = new HashMap<>(); - readConfing(configFilePath); + readConfing(); } @Override @@ -63,15 +58,10 @@ public class ChanelCommander implements Runnable { break; /* case "PART": // todo: need to track join flood? Fuck that. Track using JOIN - break; case "QUIT": // todo: need this? - break; case "TOPIC": // todo: need this? - break; case "MODE": // todo: need this? - break; - case "KICK": // todo: need this? - break; */ + case "KICK": // todo: need this? */ default: break; } @@ -240,72 +230,23 @@ public class ChanelCommander implements Runnable { executiveStr.append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))); } StreamProvider.writeToStream(server, executiveStr.toString()); + } - } - // TSV - private void parse(String[] directive){ - if (directive.length >= 3 && directive[0] != null && !directive[0].startsWith("#") && directive[1] != null && directive[2] != null){ - // System.out.println(Arrays.toString(directive)); // TODO:debug - switch (directive[0].toLowerCase()){ - case "join": - joinMap.put(directive[1], Arrays.copyOfRange(directive, 2, directive.length)); - break; - case "msg": - msgMap.put(directive[1], Arrays.copyOfRange(directive, 2, directive.length)); - break; - case "nick": - nickMap.put(directive[1], Arrays.copyOfRange(directive, 2, directive.length)); - break; - case "joinfloodcontrol": - if (!directive[1].isEmpty() && !directive[2].isEmpty() && Pattern.matches("^[0-9]+?$", directive[1].trim()) && Pattern.matches("^[0-9]+?$", directive[2].trim())) { - int events = Integer.parseInt(directive[1].trim()); - int timeFrame = Integer.parseInt(directive[2].trim()); - if (events > 0 && timeFrame > 0) { - jfh = new JoinFloodHandler(events, timeFrame, server, channel); - joinFloodTrackNeed = true; - } - else { - System.out.println("Internal issue: thread ChanelCommander->parse(): 'Number of events' and/or 'Time Frame in seconds' should be greater than 0"); - } - } - else - System.out.println("Internal issue: thread ChanelCommander->parse(): 'Number of events' and/or 'Time Frame in seconds' should be numbers greater than 0"); - break; - case "joinclonecontrol": - if (!directive[1].isEmpty() && !directive[2].isEmpty() && Pattern.matches("^[0-9]+?$", directive[1].trim())) { - int events = Integer.parseInt(directive[1].trim()); - if (events > 0){ - jch = new JoinCloneHandler(directive[2], events, server, channel); // TODO: REMOVE - joinCloneTrackNeed = true; - } - else { - System.out.println("Internal issue: thread ChanelCommander->parse(): 'Number of events' should be greater than 0"); - } - } else { - System.out.println("Internal issue: thread ChanelCommander->parse(): 'Number of events' should be greater than 0 and pattern shouldn't be empty."); - } - } - } - } private String simplifyNick(String nick){ return nick.replaceAll("!.*$",""); } - private void readConfing(String confFilesPath){ - if (!confFilesPath.endsWith(File.separator)) - confFilesPath += File.separator; + private void readConfing() throws Exception{ + ConfigurationChannel configChannel = ConfigurationManager.getConfiguration(server).getChannelConfig(channel); + joinMap = configChannel.getJoinMap(); + msgMap = configChannel.getMsgMap(); + nickMap = configChannel.getNickMap(); - File file = new File(confFilesPath+server+ channel +".csv"); // TODO: add/search for filename - - if (!file.exists()) - return; - try { - BufferedReader br = new BufferedReader(new FileReader(file)); - String line; - while ((line = br.readLine()) != null) { - parse(line.split("\t")); - } + if (configChannel.isJoinFloodControl()) { + jfh = new JoinFloodHandler(configChannel.getJoinFloodControlEvents(), configChannel.getJoinFloodControlTimeframe(), server, channel); + joinFloodTrackNeed = true; } - catch (Exception e) { - System.out.println("Internal issue: thread ChanelCommander->readConfig():\t\n"+e.getMessage()); + if (configChannel.isJoinCloneControl()) { + jch = new JoinCloneHandler(configChannel.getJoinCloneControlPattern(), configChannel.getJoinCloneControlTimeframe(), server, channel); // TODO: REMOVE + joinCloneTrackNeed = true; } } } \ No newline at end of file diff --git a/src/main/java/InnaIrcBot/GlobalData.java b/src/main/java/InnaIrcBot/GlobalData.java index 1e42153..682a36d 100644 --- a/src/main/java/InnaIrcBot/GlobalData.java +++ b/src/main/java/InnaIrcBot/GlobalData.java @@ -1,14 +1,12 @@ package InnaIrcBot; -import InnaIrcBot.logging.LogDriver; - -import java.util.ArrayList; -import java.util.List; - public class GlobalData { private static final String version = "InnaIrcBot v0.8 \"Коммунарка\""; public static synchronized String getAppVersion(){ - return version; + return String.format("%s, %s %s %s", version, + System.getProperty("os.name"), + System.getProperty("os.version"), + System.getProperty("os.arch")); } public static final int CHANNEL_QUEUE_CAPACITY = 500; } diff --git a/src/main/java/InnaIrcBot/ProvidersConsumers/ChanConsumer.java b/src/main/java/InnaIrcBot/ProvidersConsumers/ChanConsumer.java index 2b95633..da713ba 100644 --- a/src/main/java/InnaIrcBot/ProvidersConsumers/ChanConsumer.java +++ b/src/main/java/InnaIrcBot/ProvidersConsumers/ChanConsumer.java @@ -6,6 +6,7 @@ import InnaIrcBot.IrcChannel; import InnaIrcBot.logging.LogDriver; import InnaIrcBot.logging.Worker; import InnaIrcBot.config.ConfigurationManager; +import InnaIrcBot.logging.WorkerZero; import java.time.LocalTime; import java.time.format.DateTimeFormatter; @@ -43,15 +44,12 @@ public class ChanConsumer implements Runnable { this.nick = ownNick; this.rejoin = ConfigurationManager.getConfiguration(serverName).getRejoinOnKick(); this.channels = channels; - // Create chanel commander thread, get pipe - getChanelCommander( - ConfigurationManager.getConfiguration(serverName).getChanelConfigurationsPath() - ); + getChanelCommander(); } // Create ChanelCommander - private void getChanelCommander(String chanelConfigurationsPath){ + private void getChanelCommander() throws Exception{ this.queue = new ArrayBlockingQueue<>(GlobalData.CHANNEL_QUEUE_CAPACITY); - ChanelCommander commander = new ChanelCommander(queue, serverName, channelName, chanelConfigurationsPath); + ChanelCommander commander = new ChanelCommander(queue, serverName, channelName); this.channelCommanderThread = new Thread(commander); this.channelCommanderThread.start(); } @@ -147,7 +145,7 @@ public class ChanConsumer implements Runnable { System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->fixLogDriverIssues(): Some issues detected. Trying to fix..."); this.writerWorker = LogDriver.getWorker(serverName, channelName); // Reset logDriver and try using the same one if (! writerWorker.logAdd(a, b, c)){ // Write to it what was not written (most likely) and if it's still not consistent: - this.writerWorker = LogDriver.getZeroWorker(); + this.writerWorker = new WorkerZero(); System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->fixLogDriverIssues(): failed to use defined LogDriver. Using ZeroWorker instead."); } } diff --git a/src/main/java/InnaIrcBot/ProvidersConsumers/DataProvider.java b/src/main/java/InnaIrcBot/ProvidersConsumers/DataProvider.java index 2a209ff..130cf96 100644 --- a/src/main/java/InnaIrcBot/ProvidersConsumers/DataProvider.java +++ b/src/main/java/InnaIrcBot/ProvidersConsumers/DataProvider.java @@ -42,9 +42,7 @@ public class DataProvider implements Runnable { ReconnectControl.register(server); - LogDriver.setLogDriver(server, - configurationFile.getLogDriverConfiguration(), - configurationFile.getApplicationLogDir()); + LogDriver.setLogDriver(server); /* Used for sending data into consumers objects*/ Map ircChannels = Collections.synchronizedMap(new HashMap<>()); @@ -77,8 +75,6 @@ public class DataProvider implements Runnable { String chan = rawStrings[2].replaceAll("(\\s.?$)|(\\s.+?$)", ""); - //System.out.println("\tChannel: "+chan+"\n\tAction: "+rawStrings[1]+"\n\tSender: "+rawStrings[0]+"\n\tMessage: "+rawStrings[2]+"\n"); - if (rawStrings[1].equals("QUIT") || rawStrings[1].equals("NICK")) { // replace regex for (IrcChannel ircChannel : ircChannels.values()) { ircChannel.getChannelQueue().add(rawStrings[1] + " " + rawStrings[0] + " " + rawStrings[2]); diff --git a/src/main/java/InnaIrcBot/config/ConfigurationChannel.java b/src/main/java/InnaIrcBot/config/ConfigurationChannel.java new file mode 100644 index 0000000..3c467ff --- /dev/null +++ b/src/main/java/InnaIrcBot/config/ConfigurationChannel.java @@ -0,0 +1,102 @@ +package InnaIrcBot.config; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class ConfigurationChannel { + + private HashMap joinMap; + private HashMap msgMap; + private HashMap nickMap; + + private boolean joinFloodControl; + private int joinFloodControlEvents; + private int joinFloodControlTimeframe; + + private boolean joinCloneControl; + private int joinCloneControlTimeframe; + private String joinCloneControlPattern; + + public ConfigurationChannel( + boolean joinFloodControl, + int joinFloodControlEvents, + int joinFloodControlSeconds, + boolean joinCloneControl, + int joinCloneControlTimeframe, + String joinCloneControlPattern, + List rules){ + + parseRules(rules); + + if (joinFloodControl) + validateJoinFloodControl(joinFloodControlEvents, joinFloodControlSeconds); + + if (joinCloneControl) + validateJoinCloneControl(joinCloneControlTimeframe, joinCloneControlPattern); + } + + private void parseRules(List rules){ + this.joinMap = new HashMap<>(); + this.msgMap = new HashMap<>(); + this.nickMap = new HashMap<>(); + + for (String rule : rules){ + parseRule(rule); + } + } + + private void parseRule(String rule){ + String[] directive = rule.split("\t"); + + if (isNotValidDirective(directive)) + return; + + switch (directive[0].toLowerCase()){ + case "join": + joinMap.put(directive[1], Arrays.copyOfRange(directive, 2, directive.length)); + break; + case "msg": + msgMap.put(directive[1], Arrays.copyOfRange(directive, 2, directive.length)); + break; + case "nick": + nickMap.put(directive[1], Arrays.copyOfRange(directive, 2, directive.length)); + break; + } + } + private boolean isNotValidDirective(String[] directive){ + return directive.length < 3 || directive[0] == null || directive[1] == null || directive[2] == null; + } + + private void validateJoinFloodControl(int events, int timeFrame){ + if (events <= 0 && timeFrame <= 0) { + System.out.println("Join Flood Control configuration issue: 'Join number' and 'time frame' should be greater than 0."); + return; + } + joinFloodControl = true; + joinFloodControlEvents = events; + joinFloodControlTimeframe = timeFrame; + } + + private void validateJoinCloneControl(int timeFrame, String pattern){ + if (timeFrame < 0) { + System.out.println("Join Clone Control configuration issue: 'time frame' should be greater than 0"); + return; + } + joinCloneControl = true; + joinCloneControlTimeframe = timeFrame; + joinCloneControlPattern = pattern; + } + + public HashMap getJoinMap() { return joinMap; } + public HashMap getMsgMap() { return msgMap; } + public HashMap getNickMap() { return nickMap; } + + public boolean isJoinFloodControl() { return joinFloodControl; } + public int getJoinFloodControlEvents() { return joinFloodControlEvents; } + public int getJoinFloodControlTimeframe() { return joinFloodControlTimeframe; } + + public boolean isJoinCloneControl() { return joinCloneControl; } + public int getJoinCloneControlTimeframe() { return joinCloneControlTimeframe; } + public String getJoinCloneControlPattern() { return joinCloneControlPattern; } +} diff --git a/src/main/java/InnaIrcBot/config/ConfigurationFile.java b/src/main/java/InnaIrcBot/config/ConfigurationFile.java index 4eeba65..667321f 100644 --- a/src/main/java/InnaIrcBot/config/ConfigurationFile.java +++ b/src/main/java/InnaIrcBot/config/ConfigurationFile.java @@ -1,10 +1,19 @@ package InnaIrcBot.config; +import org.ini4j.Config; +import org.ini4j.Ini; +import org.ini4j.Wini; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + public class ConfigurationFile { private String serverName; private int serverPort; private String serverPass; - private String[] channels; private String userNick; private String userIdent; private String userRealName; @@ -12,73 +21,143 @@ public class ConfigurationFile { private String userNickAuthStyle; private String userMode; private boolean rejoinOnKick; - private String logDriver; - private String[] logDriverParameters; private String botAdministratorPassword; - private String chanelConfigurationsPath; private String applicationLogDir; - private LogDriverConfiguration logDriverConfiguration; + private List channels; + private HashMap channelConfigs; - public ConfigurationFile(String serverName, - int serverPort, - String serverPass, - String[] channels, - String userNick, - String userIdent, - String userRealName, - String userNickPass, - String userNickAuthStyle, - String userMode, - boolean rejoinOnKick, - String logDriver, - String[] logDriverParameters, - String botAdministratorPassword, - String chanelConfigurationsPath, - String applicationLogDir){ - this.serverName = serverName; - this.serverPort = serverPort; - this.serverPass = serverPass; - this.channels = channels; - this.userIdent = userIdent; - this.userNick = userNick; - this.userRealName = userRealName; - this.userNickPass = userNickPass; - this.userNickAuthStyle = userNickAuthStyle; - this.userMode = userMode; - this.rejoinOnKick = rejoinOnKick; - this.logDriver = logDriver; - this.logDriverParameters = logDriverParameters; - this.botAdministratorPassword = botAdministratorPassword; - this.chanelConfigurationsPath = chanelConfigurationsPath; - this.applicationLogDir = applicationLogDir; - } - - public String getServerName() { return nonNullString(serverName); } + public String getServerName() { return serverName; } public int getServerPort() { return serverPort; } - public String getServerPass() { return nonNullString(serverPass); } - public String[] getChannels() { return channels; } - public String getUserNick() { return nonNullString(userNick); } - public String getUserIdent() { return nonNullString(userIdent); } - public String getUserRealName() { return nonNullString(userRealName); } - public String getUserNickPass() { return nonNullString(userNickPass); } - public String getUserNickAuthStyle() { return nonNullString(userNickAuthStyle); } - public String getUserMode() { return nonNullString(userMode); } + public String getServerPass() { return serverPass; } + public String getUserNick() { return userNick; } + public String getUserIdent() { return userIdent; } + public String getUserRealName() { return userRealName; } + public String getUserNickPass() { return userNickPass; } + public String getUserNickAuthStyle() { return userNickAuthStyle; } + public String getUserMode() { return userMode; } public boolean getRejoinOnKick() { return rejoinOnKick; } + public String getBotAdministratorPassword() { return botAdministratorPassword; } + public String getApplicationLogDir() { return applicationLogDir; } + public LogDriverConfiguration getLogDriverConfiguration(){ return logDriverConfiguration; } + public List getChannels() { return channels; } + public ConfigurationChannel getChannelConfig(String channel) { return channelConfigs.get(channel); } - public LogDriverConfiguration getLogDriverConfiguration(){ - return new LogDriverConfiguration(nonNullString(logDriver).toLowerCase(), logDriverParameters); + public ConfigurationFile(String pathToConfigurationFile) throws Exception{ + Wini ini = new Wini(); + ini.setConfig(getConfig()); + ini.load(new File(pathToConfigurationFile)); + parseMain(ini); + parseLogging(ini); + parseChannels(ini); + validate(); } - public String getBotAdministratorPassword() { return nonNullString(botAdministratorPassword); } - public String getChanelConfigurationsPath() { return nonNullString(chanelConfigurationsPath); } - public String getApplicationLogDir() { return nonNullString(applicationLogDir); } - - public void setUserNickAuthStyle(String userNickAuthStyle) { - this.userNickAuthStyle = userNickAuthStyle; + private Config getConfig(){ + Config config = new Config(); + config.setFileEncoding(StandardCharsets.UTF_8); + config.setMultiOption(true); + config.setEscape(true); + return config; } - private String nonNullString(String value){ - return value == null ? "" : value; + private void parseMain(Wini ini){ + Ini.Section mainSection = ini.get("main"); + + this.serverName = mainSection.getOrDefault("server name", ""); + this.serverPort = mainSection.get("server port", int.class); + this.serverPass = mainSection.getOrDefault("server password", ""); + this.userNick = mainSection.getOrDefault("nickname", ""); + this.userIdent = mainSection.getOrDefault("ident", ""); + this.userRealName = mainSection.getOrDefault("real name", ""); + this.userNickPass = mainSection.getOrDefault("nickname password", ""); + this.userNickAuthStyle = mainSection.getOrDefault("nickserv auth method", "").toLowerCase(); + this.userMode = mainSection.getOrDefault("user modes", ""); + this.rejoinOnKick = mainSection.get("auto rejoin", boolean.class); + this.botAdministratorPassword = mainSection.getOrDefault("bot administrator password", ""); + this.applicationLogDir = mainSection.getOrDefault("application logs", ""); + } + + private void parseChannels(Wini ini){ + Ini.Section channelsSection = ini.get("channels"); + this.channels = channelsSection.getAll("channel"); + this.channelConfigs = new HashMap<>(); + for (String channel: channels){ + addNewChannelConfiguration(ini, channel); + } + } + private void addNewChannelConfiguration(Wini ini, String channelName){ + Ini.Section channelSection = ini.get(channelName); + + if (channelSection == null) + return; + + Ini.Section rulesChannelSection = channelSection.getChild("rules"); + + List channelRules = rulesChannelSection.getAll("rule"); //TODO: check not-null + + if (channelRules == null) + channelRules = new ArrayList<>(); + + Ini.Section joinFloodControlSection = channelSection.getChild("rules"); + + boolean joinFloodControl = joinFloodControlSection.get("enable", boolean.class); + int joinFloodControlEventsNumber = -1; + int joinFloodControlTimeFrame = -1; + if (joinFloodControl){ + joinFloodControlEventsNumber = joinFloodControlSection.get("join number", int.class); + joinFloodControlTimeFrame = joinFloodControlSection.get("time frame", int.class); + } + + Ini.Section joinCloneControlSection = channelSection.getChild("rules"); + + boolean joinCloneControl = joinCloneControlSection.get("enable", boolean.class);; + int joinCloneControlTimeFrame = -1; + String joinCloneControlPattern = ""; + if (joinCloneControl){ + joinCloneControlTimeFrame = joinCloneControlSection.get("time frame", int.class); + joinCloneControlPattern = joinCloneControlSection.getOrDefault("pattern", ""); + } + + channelConfigs.put(channelName, new ConfigurationChannel( + joinFloodControl, + joinFloodControlEventsNumber, + joinFloodControlTimeFrame, + joinCloneControl, + joinCloneControlTimeFrame, + joinCloneControlPattern, + channelRules)); + } + + private void parseLogging(Wini ini){ + Ini.Section channelsSection = ini.get("logging"); + + this.logDriverConfiguration = new LogDriverConfiguration( + channelsSection.getOrDefault("driver", ""), + channelsSection.getOrDefault("file(s) location", ""), + channelsSection.getOrDefault("MongoDB host:port", ""), + channelsSection.getOrDefault("MongoDB DB table", ""), + channelsSection.getOrDefault("MongoDB DB user", ""), + channelsSection.getOrDefault("MongoDB DB password", "") + ); + } + //TODO: more validation + private void validate() throws Exception{ + if (serverName.isEmpty()) + throw new Exception("Server not defined in configuration file."); + + if (serverPort <= 0 || serverPort > 65535) + throw new Exception("Server port number cannot be less/equal zero or greater then 65535"); + + if (userNick.isEmpty()) + throw new Exception("Configuration issue: no nickname specified. "); + + if (! userNickPass.isEmpty()) { + if (userNickAuthStyle.isEmpty()) + throw new Exception("Configuration issue: password specified while auth method is not."); + + if ( ! userNickAuthStyle.equals("rusnet") && ! userNickAuthStyle.equals("freenode")) + throw new Exception("Configuration issue: userNickAuthStyle could be freenode or rusnet."); + } } } diff --git a/src/main/java/InnaIrcBot/config/ConfigurationFileGenerator.java b/src/main/java/InnaIrcBot/config/ConfigurationFileGenerator.java index c5d3f03..2f24c41 100644 --- a/src/main/java/InnaIrcBot/config/ConfigurationFileGenerator.java +++ b/src/main/java/InnaIrcBot/config/ConfigurationFileGenerator.java @@ -1,13 +1,15 @@ package InnaIrcBot.config; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; +import org.ini4j.*; +import org.ini4j.spi.EscapeTool; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; public class ConfigurationFileGenerator { private String fileLocation; @@ -28,7 +30,6 @@ public class ConfigurationFileGenerator { } createConfigurationFile(); - System.out.println("Configuration file created: " + this.fileLocation); // TODO: Move to l4j } catch (IOException e){ System.out.println("Unable to write configuration file: \n\t"+e.getMessage()); @@ -38,7 +39,7 @@ public class ConfigurationFileGenerator { private void setLocationDefault(){ fileLocation = System.getProperty("user.dir") + File.separator - + "myBotConfig.conf"; + + "innaircbot.conf"; } private boolean locationNotDefined(){ @@ -52,16 +53,17 @@ public class ConfigurationFileGenerator { private void setLocationInsideFolder() throws IOException{ createFoldersIfNeeded(); if (fileLocation.endsWith(File.separator)) - fileLocation = fileLocation + "myBotConfig.conf"; + fileLocation = fileLocation + "innaircbot.conf"; else - fileLocation = fileLocation + File.separator + "myBotConfig.conf"; + fileLocation = fileLocation + File.separator + "innaircbot.conf"; } private void createFoldersIfNeeded() throws IOException{ Path folderPath = Paths.get(fileLocation); if (! Files.exists(folderPath)) Files.createDirectories(folderPath); } - private void createConfigurationFile() throws IOException{ + /* + private void createConfigurationFileOld() throws IOException{ File configurationFile = new File(this.fileLocation); Writer writerFile = new OutputStreamWriter(new FileOutputStream(configurationFile.getAbsolutePath()), StandardCharsets.UTF_8); @@ -78,7 +80,7 @@ public class ConfigurationFileGenerator { "freenode", "ix", true, - "Files", + "files", new String[] {System.getProperty("user.home")}, "pswd", System.getProperty("user.home"), @@ -89,4 +91,91 @@ public class ConfigurationFileGenerator { writingStorageObject.toJson(configurationFileObject, writerFile); writerFile.close(); } + */ + private void createConfigurationFile() throws IOException{ + final String mainSectionName = "main"; + final String channelSectionName = "channels"; + + List channels = new ArrayList<>(); + channels.add("#main"); + channels.add("#lpr"); + List logDriverPreferences = new ArrayList<>(); + logDriverPreferences.add(System.getProperty("user.home")); + + File configurationFile = new File(this.fileLocation); + + Config myConfig = new Config(); + myConfig.setFileEncoding(StandardCharsets.UTF_8); + myConfig.setMultiOption(true); + myConfig.setEscape(true); + //myConfig.setEmptyOption(true); + //myConfig.setComment(true); + + Wini ini = new Wini(); + ini.setConfig(myConfig); + + Ini.Section mainSection = ini.add(mainSectionName); + mainSection.put( "server name", "srv"); + mainSection.put( "server port", 6667); + mainSection.put( "server password", ""); + mainSection.put( "nickname", "InnaIrcBot"); + mainSection.put( "ident", "sweethome"); + mainSection.put( "real name", "bot"); + mainSection.put( "nickname password", ""); + mainSection.put( "nickserv auth method", "freenode"); + mainSection.put( "user modes", "i"); + mainSection.put( "auto rejoin", true); + mainSection.put( "bot administrator password", "i_pswd"); + mainSection.put( "application logs", "/tmp"); + + Ini.Section loggingSection = ini.add("logging"); + loggingSection.put( "driver", "files"); + loggingSection.put("file(s) location", ""); + loggingSection.put("MongoDB host:port", ""); + loggingSection.put("MongoDB DB table", ""); + loggingSection.put("MongoDB DB user", ""); + loggingSection.put("MongoDB DB password", ""); + + Ini.Section channelsSection = ini.add(channelSectionName); + channelsSection.putAll("channel", channels); + + Ini.Section channelMainSection = ini.add( channels.get(0) ); + + Ini.Section channelMainRulesSection = channelMainSection.addChild("rules"); + channelMainRulesSection.add("rule","join\t^cv.*\t\\cversion\t(^.+(\\s|\\t)+)"); + channelMainRulesSection.add("rule","msg\t^cv.*\t\\cversion\t(^.+(\\s|\\t)+)"); + channelMainRulesSection.add("rule", "join\t^BadGuy1(.+)?!.*\t\\kickban\trequested\\privmsg\tNever come back"); + channelMainRulesSection.add("rule", "join\t^BadGuy2(.+)?!.*\t\\kick\tkick!"); + channelMainRulesSection.add("rule", "join\t^BadGuy3(.+)?!.*\t\\ban\tban!"); + channelMainRulesSection.add("rule", "nick\t^BadNickname.*\t\\chanmsg\tstop it!\n"); + channelMainRulesSection.add("rule", "nick\t^Billilish.*\t\\voice"); + + channelMainRulesSection.add("rule", "msg\t^cci.*\t\\cclientinfo\t\t(^.+(\\s|\\t)+)\tThere are no "); + channelMainRulesSection.add("rule", "msg\t^cf.*\t\\cfinger\t(^.+(\\s|\\t)+)\tI \t D\t K"); + channelMainRulesSection.add("rule", "msg\t^cp.*\t\\cping\t\t(^.+(\\s|\\t)+)\tlol"); + channelMainRulesSection.add("rule", "msg\t^cs.*\t\\csource\t(^.+(\\s|\\t)+)\tpiu-\tpiu\t: "); + channelMainRulesSection.add("rule", "msg\t^ct.*\t\\ctime\t\t(^.+(\\s|\\t)+)\tOoops:"); + channelMainRulesSection.add("rule", "msg\t^cui.*\t\\cuserinfo\t(^.+(\\s|\\t)+)\tNope: "); + channelMainRulesSection.add("rule", "msg\t^cv.*\t\\cversion\t(^.+(\\s|\\t)+)"); + channelMainRulesSection.add("rule", "msg\t^pci.*\t\\pclientinfo\t(^.+(\\s|\\t)+)\tkek: "); + channelMainRulesSection.add("rule", "msg\t^pf.*\t\\pfinger\t(^.+(\\s|\\t)+)\t\tNobody like: "); + channelMainRulesSection.add("rule", "msg\t^pp.*\t\\pping\t\t(^.+(\\s|\\t)+)\tnope: "); + channelMainRulesSection.add("rule", "msg\t^ps.*\t\\psource\t(^.+(\\s|\\t)+)\t\tNooo "); + channelMainRulesSection.add("rule", "msg\t^pt.*\t\\ptime\t\t(^.+(\\s|\\t)+)\tHo-ho-ho: "); + channelMainRulesSection.add("rule", "msg\t^pu.*\t\\puserinfo\t(^.+(\\s|\\t)+)\tSome random text: "); + channelMainRulesSection.add("rule", "msg\t^pv.*\t\\pversion\t(^.+(\\s|\\t)+)\t\\chanmsg\tsent!"); + + + Ini.Section channelMainJoinFloodControlSection = channelMainSection.addChild("JoinFloodControl"); + channelMainJoinFloodControlSection.put("enable", true); + channelMainJoinFloodControlSection.put("join number", 3); + channelMainJoinFloodControlSection.put("time frame", 60); + + Ini.Section channelMainJoinCloneControlSection = channelMainSection.addChild("JoinCloneControl"); + channelMainJoinCloneControlSection.put("enable", false); + channelMainJoinCloneControlSection.put("pattern", "^.+[0-9]+?!.*$"); + channelMainJoinFloodControlSection.put("time frame", 0); + + ini.store(configurationFile); + } } diff --git a/src/main/java/InnaIrcBot/config/ConfigurationFileReader.java b/src/main/java/InnaIrcBot/config/ConfigurationFileReader.java deleted file mode 100644 index ed9b59b..0000000 --- a/src/main/java/InnaIrcBot/config/ConfigurationFileReader.java +++ /dev/null @@ -1,50 +0,0 @@ -package InnaIrcBot.config; - -import com.google.gson.Gson; - -import java.io.*; - -public class ConfigurationFileReader { - private ConfigurationFileReader(){} - - static ConfigurationFile read(String pathToFile) throws Exception{ // TODO: NULL or object - ConfigurationFile storageObject; - - File configFile = new File(pathToFile); - - try (Reader fileReader = new InputStreamReader(new FileInputStream(configFile))) { - storageObject = new Gson().fromJson(fileReader, ConfigurationFile.class); - } - - validate(storageObject); - - return storageObject; - } - - private static void validate(ConfigurationFile configurationFile) throws Exception{ //TODO: more validation - if (configurationFile.getServerName().isEmpty()) - throw new Exception("Server not defined in configuration file."); - - if (configurationFile.getServerPort() <= 0) - throw new Exception("Server port set incorrectly in configuration file."); - - String nick = configurationFile.getUserNick(); - if (nick.isEmpty()) - throw new Exception("Configuration issue: no nickname specified. "); - - if (! configurationFile.getUserNickPass().isEmpty()) { - if (configurationFile.getUserNickAuthStyle().isEmpty()) - throw new Exception("Configuration issue: password specified while auth method is not."); - - configurationFile.setUserNickAuthStyle( configurationFile.getUserNickAuthStyle().toLowerCase() ); - - if ( ! configurationFile.getUserNickAuthStyle().equals("rusnet") && ! configurationFile.getUserNickAuthStyle().equals("freenode")) - throw new Exception("Configuration issue: userNickAuthStyle could be freenode or rusnet."); - } - - if (configurationFile.getServerPort() <= 0 || configurationFile.getServerPort() > 65535) - throw new Exception("Server port number cannot be less/equal zero or greater then 65535"); - } - - -} diff --git a/src/main/java/InnaIrcBot/config/ConfigurationManager.java b/src/main/java/InnaIrcBot/config/ConfigurationManager.java index c5ec99e..7de9bae 100644 --- a/src/main/java/InnaIrcBot/config/ConfigurationManager.java +++ b/src/main/java/InnaIrcBot/config/ConfigurationManager.java @@ -8,7 +8,7 @@ public class ConfigurationManager { private final static Map configurations = Collections.synchronizedMap(new HashMap<>()); public static ConfigurationFile readAndSetConfiguration(String pathToConfigurationFile) throws Exception{ - ConfigurationFile configurationFile = ConfigurationFileReader.read(pathToConfigurationFile); + ConfigurationFile configurationFile = new ConfigurationFile(pathToConfigurationFile); configurations.put(configurationFile.getServerName(), configurationFile); return configurationFile; } diff --git a/src/main/java/InnaIrcBot/config/LogDriverConfiguration.java b/src/main/java/InnaIrcBot/config/LogDriverConfiguration.java index 9e079e4..0997799 100644 --- a/src/main/java/InnaIrcBot/config/LogDriverConfiguration.java +++ b/src/main/java/InnaIrcBot/config/LogDriverConfiguration.java @@ -4,37 +4,81 @@ import InnaIrcBot.logging.SupportedLogDrivers; public class LogDriverConfiguration { private String name; - private String[] params; - public LogDriverConfiguration(String name, String[] params){ + private final String path; + + private final String mongoURI; + private final String mongoTable; + private String mongoUser; + private String mongoPassword; + + public LogDriverConfiguration( + String name, + String path, + String mongoURI, + String mongoTable, + String mongoUser, + String mongoPassword) + { this.name = name.toLowerCase(); - this.params = params; + this.path = path; + this.mongoURI = mongoURI; + this.mongoTable = mongoTable; + this.mongoUser = mongoUser; + this.mongoPassword = mongoPassword; validateName(); - validateParams(); + validateConfiguration(); } private void validateName(){ if (! SupportedLogDrivers.contains(name)) { name = SupportedLogDrivers.zero; } } - private void validateParams(){ - if (params == null) { - name = SupportedLogDrivers.zero; - return; + + private void validateConfiguration(){ + switch (this.name){ + case SupportedLogDrivers.files: + case SupportedLogDrivers.sqlite: + validatePath(); + break; + case SupportedLogDrivers.mongodb: + validateMongo(); + break; } - if (params.length == 0){ - name = SupportedLogDrivers.zero; - return; + } + + private void validatePath(){ + try { + checkFieldNotEmpty(path); } - if (params[0] == null){ - name = SupportedLogDrivers.zero; - return; - } - if (params[0].isEmpty()){ + catch (Exception e){ name = SupportedLogDrivers.zero; } } + private void validateMongo(){ + try { + checkFieldNotEmpty(mongoURI); + checkFieldNotEmpty(mongoTable); + if (mongoUser == null) + mongoUser = ""; + if (mongoPassword == null) + mongoPassword = ""; + } + catch (Exception e){ + name = SupportedLogDrivers.zero; + } + } + private void checkFieldNotEmpty(String field) throws Exception{ + if (field == null || field.isEmpty()) { + throw new Exception(); + } + } + public String getName() { return name; } - public String[] getParams() { return params; } + public String getPath() { return path; } + public String getMongoURI() { return mongoURI; } + public String getMongoTable() { return mongoTable; } + public String getMongoUser() { return mongoUser; } + public String getMongoPassword() { return mongoPassword; } } diff --git a/src/main/java/InnaIrcBot/logging/LogDriver.java b/src/main/java/InnaIrcBot/logging/LogDriver.java index 037aa31..0089d5e 100644 --- a/src/main/java/InnaIrcBot/logging/LogDriver.java +++ b/src/main/java/InnaIrcBot/logging/LogDriver.java @@ -1,62 +1,52 @@ package InnaIrcBot.logging; -import InnaIrcBot.ProvidersConsumers.StreamProvider; +import InnaIrcBot.config.ConfigurationFile; +import InnaIrcBot.config.ConfigurationManager; import InnaIrcBot.config.LogDriverConfiguration; import java.util.HashMap; public class LogDriver { - private final static HashMap serverDriver = new HashMap<>(); private final static HashMap systemLogWorkerMap = new HashMap<>(); - /** - * Define driver for desired server - * */ - // TODO: add proxy worker for using with multiple drivers - public static synchronized void setLogDriver(String server, - LogDriverConfiguration logDriverConfiguration, - String applicationLogDir){ - String[][] drvAndParams = { - {logDriverConfiguration.getName()}, - logDriverConfiguration.getParams() - }; - serverDriver.put(server, drvAndParams); + + // TODO: add proxy multiple drivers support + public static synchronized void setLogDriver(String server){ + String applicationLogDir; + try { + applicationLogDir = ConfigurationManager.getConfiguration(server).getApplicationLogDir(); + } + catch (Exception e){ + applicationLogDir = ""; + } systemLogWorkerMap.put(server, new WorkerSystem(server, applicationLogDir)); } public static synchronized Worker getWorker(String server, String channel){ - if (serverDriver.containsKey(server)) { - switch (serverDriver.get(server)[0][0]) { + try { + ConfigurationFile serverConfiguration = ConfigurationManager.getConfiguration(server); + LogDriverConfiguration logDriverConfiguration = serverConfiguration.getLogDriverConfiguration(); + + switch (logDriverConfiguration.getName()) { case "files": - WorkerFiles workerFiles = new WorkerFiles(server, serverDriver.get(server)[1], channel); - return validateConsistancy(workerFiles, server, channel); + return new WorkerFiles(server, logDriverConfiguration, channel); case "sqlite": - WorkerSQLite workerSQLite = new WorkerSQLite(server, serverDriver.get(server)[1], channel); - return validateConsistancy(workerSQLite, server, channel); + return new WorkerSQLite(server, logDriverConfiguration, channel); case "mongodb": - WorkerMongoDB workerMongoDB = new WorkerMongoDB(server, serverDriver.get(server)[1], channel); - return validateConsistancy(workerMongoDB, server, channel); + return new WorkerMongoDB(server, logDriverConfiguration, channel); case "zero": + default: return new WorkerZero(); } } - System.out.println("Issue on BotDriver->getWorker(): Channel requested for non-existing server?\n" + - "\tUsing ZeroWorker."); - return new WorkerZero(); + catch (Exception e){ + System.out.println("Issue on BotDriver->getWorker(): Channel requested for non-existing server? " + + e.getMessage() + + "\n\tUsing ZeroWorker."); + return new WorkerZero(); + } } - // If channel found that it's impossible to use defined worker from user settings and asking for use ZeroWorker - public static synchronized Worker getZeroWorker(){ return new WorkerZero(); } public static synchronized WorkerSystem getSystemWorker(String serverName){ return systemLogWorkerMap.get(serverName); } - - private static Worker validateConsistancy(Worker worker, String server, String channel){ // synchronized? - if (worker.isConsistent()){ - return worker; - } - System.out.println("BotDriver->validateConstancy(): Unable to use " - +worker.getClass().getSimpleName()+" for "+server+"/"+channel - +". Using ZeroWorker instead."); - return new WorkerZero(); - } } diff --git a/src/main/java/InnaIrcBot/logging/WorkerFiles.java b/src/main/java/InnaIrcBot/logging/WorkerFiles.java index 58f817e..be86f1c 100644 --- a/src/main/java/InnaIrcBot/logging/WorkerFiles.java +++ b/src/main/java/InnaIrcBot/logging/WorkerFiles.java @@ -1,5 +1,7 @@ package InnaIrcBot.logging; +import InnaIrcBot.config.LogDriverConfiguration; + import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -17,10 +19,10 @@ public class WorkerFiles implements Worker { private boolean consistent; - public WorkerFiles(String server, String[] driverParameters, String channel){ + public WorkerFiles(String server, LogDriverConfiguration logDriverConfiguration, String channel){ this.channel = channel.replaceAll(File.separator, ","); - formatFilePath(server, driverParameters); + formatFilePath(server, logDriverConfiguration.getPath()); try { createServerFolder(); @@ -31,9 +33,7 @@ public class WorkerFiles implements Worker { } } - private void formatFilePath(String server, String[] driverParameters){ - String dirLocation = driverParameters[0].trim(); // TODO: MOVE trim() out of here - + private void formatFilePath(String server, String dirLocation){ if (! dirLocation.endsWith(File.separator)) dirLocation += File.separator; diff --git a/src/main/java/InnaIrcBot/logging/WorkerMongoDB.java b/src/main/java/InnaIrcBot/logging/WorkerMongoDB.java index 5012c52..63a3c8b 100644 --- a/src/main/java/InnaIrcBot/logging/WorkerMongoDB.java +++ b/src/main/java/InnaIrcBot/logging/WorkerMongoDB.java @@ -1,5 +1,6 @@ package InnaIrcBot.logging; +import InnaIrcBot.config.LogDriverConfiguration; import com.mongodb.*; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; @@ -24,27 +25,15 @@ public class WorkerMongoDB implements Worker { //TODO consider ski private MongoCollection collection; private boolean consistent; - public WorkerMongoDB(String server, String[] driverParameters, String channel){ + public WorkerMongoDB(String server, LogDriverConfiguration logDriverConfiguration, String channel) throws Exception{ this.server = server; - if (driverParameters.length < 2) - return; - if (driverParameters[0].isEmpty()) - return; - if (driverParameters[1].isEmpty()) - return; + String mongoHostAddress = logDriverConfiguration.getMongoURI(); + String mongoDBName = logDriverConfiguration.getMongoTable(); + String mongoUser = logDriverConfiguration.getMongoUser(); + String mongoPass = logDriverConfiguration.getMongoPassword(); - String mongoHostAddress = driverParameters[0]; - String mongoDBName = driverParameters[1]; - - String mongoUser; - String mongoPass; - - if (driverParameters.length == 4 && !driverParameters[2].isEmpty() && !driverParameters[3].isEmpty()) { - mongoUser = driverParameters[2]; - mongoPass = driverParameters[3]; - } - else { // Consider that DB does not require auth, therefore any credentials are fine, since not null ;) + if (mongoUser.isEmpty()) {// Consider that DB does not require auth, therefore any credentials are fine, since not null ;) mongoUser = "anon"; mongoPass = "anon"; } @@ -108,27 +97,12 @@ public class WorkerMongoDB implements Worker { //TODO consider ski Document ping = new Document("ping", 1); // - try { - Document answer = mongoDB.runCommand(ping); // reports to monitor thread if some fuckups happens - if (answer.get("ok") == null || (Double)answer.get("ok") != 1.0d){ - close(server); - return; - } - consistent = true; - } catch (MongoCommandException mce){ - System.out.println("BotMongoWorker (@"+this.server +"): Command exception. Check if username/password set correctly."); - close(server); // server received by constructor, not this.server - } catch (MongoTimeoutException mte) { - System.out.println("BotMongoWorker (@"+this.server +"): Timeout exception."); - close(server); // server received by constructor, not this.server - }catch (MongoException me){ - System.out.println("BotMongoWorker (@"+this.server +"): MongoDB Exception."); - close(server); // server received by constructor, not this.server - } catch (IllegalStateException ise){ - System.out.println("BotMongoWorker (@"+this.server +"): Illegal state exception: MongoDB server already closed (not an issue)."); - consistent = false; - // no need to close() obviously + Document answer = mongoDB.runCommand(ping); // reports to monitor thread if some fuckups happens + if (answer.get("ok") == null || (Double)answer.get("ok") != 1.0d){ + close(server); + return; } + consistent = true; setClosable(); } diff --git a/src/main/java/InnaIrcBot/logging/WorkerSQLite.java b/src/main/java/InnaIrcBot/logging/WorkerSQLite.java index 1026efa..dd173be 100644 --- a/src/main/java/InnaIrcBot/logging/WorkerSQLite.java +++ b/src/main/java/InnaIrcBot/logging/WorkerSQLite.java @@ -1,5 +1,6 @@ package InnaIrcBot.logging; +import InnaIrcBot.config.LogDriverConfiguration; import org.sqlite.SQLiteConfig; import org.sqlite.SQLiteOpenMode; @@ -12,139 +13,129 @@ public class WorkerSQLite implements Worker { private boolean consistent = false; private PreparedStatement preparedStatement; - private String ircServer; + private final String server; /** * Don't even think of changing this balalaika. * */ - public WorkerSQLite(String server, String[] driverParameters, String channel){ // TODO: threads on SQLite level // remember: One file one DB - this.ircServer = server; - driverParameters[0] = driverParameters[0].trim(); - File dir = new File(driverParameters[0]); - try { - dir.mkdirs(); // ignore result, because if it's already exists we're good. Otherwise, it will be created. Only issue that can occur is SecurityException thrown, so let's catch it. - } catch (Exception e){ - System.out.println("BotSQLiteWorker (@"+server+")->constructor(): Failure:\n\tUnable to create directory to store DB file: \n\t" +e); - return; // consistent = false; - } - if (!dir.exists()) { // probably we might want to try-catch SecurityException, but if it appeared, it has been appeared already in previous block - System.out.println("BotSQLiteWorker (@"+server+")->constructor(): Failure:\n\tUnable to create directory to store DB file: " + driverParameters[0]); - return; // consistent = false; + public WorkerSQLite(String server, LogDriverConfiguration logDriverConfiguration, String channel) throws Exception{ // TODO: threads on SQLite level // remember: One file one DB + this.server = server; + String dbFileLocation = logDriverConfiguration.getPath(); + File dir = new File(dbFileLocation); + dir.mkdirs(); // ignore result, because if it's already exists we're good. Otherwise, it will be created. Only issue that can occur is SecurityException thrown, so let's catch it. + + if (!dir.exists()) { + throw new Exception("BotSQLiteWorker (@"+server+")->constructor(): Failure:\n\tUnable to create directory to store DB file: " + dbFileLocation); } String connectionURL; - if (driverParameters[0].endsWith(File.separator)) - connectionURL = "jdbc:sqlite:"+driverParameters[0]+server+".db"; + if (dbFileLocation.endsWith(File.separator)) + connectionURL = "jdbc:sqlite:"+dbFileLocation+server+".db"; else - connectionURL = "jdbc:sqlite:"+driverParameters[0]+File.separator+server+".db"; + connectionURL = "jdbc:sqlite:"+dbFileLocation+File.separator+server+".db"; channel = channel.trim().replaceAll("\"","\\\""); // TODO: use trim in every driver/worker? - try { - SQLiteConfig sqlConfig = new SQLiteConfig(); - sqlConfig.setOpenMode(SQLiteOpenMode.NOMUTEX); //SQLITE_OPEN_NOMUTEX : multithreaded mode - this.connection = DriverManager.getConnection(connectionURL, sqlConfig.toProperties()); - if (connection != null){ - // Create table if not created - Statement statement = connection.createStatement(); - String query = "CREATE TABLE IF NOT EXISTS \""+channel+"\" (" - + " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," - + " unixtime INTEGER," - + " event TEXT," - + " subject TEXT," - + " message TEXT," - + " object TEXT" - +");"; - statement.executeUpdate(query); + SQLiteConfig sqlConfig = new SQLiteConfig(); + sqlConfig.setOpenMode(SQLiteOpenMode.NOMUTEX); //SQLITE_OPEN_NOMUTEX : multithreaded mode - // Check table representation - ResultSet rs = statement.executeQuery("PRAGMA table_info(\""+channel+"\");"); // executeQuery never null - boolean[] schemaResultCheck = {false, false, false, false, false, false}; + this.connection = DriverManager.getConnection(connectionURL, sqlConfig.toProperties()); + if (connection != null){ + // Create table if not created + Statement statement = connection.createStatement(); + String query = "CREATE TABLE IF NOT EXISTS \""+channel+"\" (" + + " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + + " unixtime INTEGER," + + " event TEXT," + + " subject TEXT," + + " message TEXT," + + " object TEXT" + +");"; + statement.executeUpdate(query); - while (rs.next()) { - switch (rs.getInt("cid")) { - case 0: - if (rs.getString("name").equals("id") - && rs.getString("type").equals("INTEGER") - && (rs.getInt("notnull") == 1) - && (rs.getString("dflt_value") == null) - && (rs.getInt("pk") == 1)) - schemaResultCheck[0] = true; - //System.out.println("Got 0"); - break; - case 1: - if (rs.getString("name").equals("unixtime") - && rs.getString("type").equals("INTEGER") - && (rs.getInt("notnull") == 0) - && (rs.getString("dflt_value") == null) - && (rs.getInt("pk") == 0)) - schemaResultCheck[1] = true; - //System.out.println("Got 1"); - break; - case 2: - if (rs.getString("name").equals("event") - && rs.getString("type").equals("TEXT") - && (rs.getInt("notnull") == 0) - && (rs.getString("dflt_value") == null) - && (rs.getInt("pk") == 0)) - schemaResultCheck[2] = true; - //System.out.println("Got 2"); - break; - case 3: - if (rs.getString("name").equals("subject") - && rs.getString("type").equals("TEXT") - && (rs.getInt("notnull") == 0) - && (rs.getString("dflt_value") == null) - && (rs.getInt("pk") == 0)) - schemaResultCheck[3] = true; - //System.out.println("Got 3"); - break; - case 4: - if (rs.getString("name").equals("message") - && rs.getString("type").equals("TEXT") - && (rs.getInt("notnull") == 0) - && (rs.getString("dflt_value") == null) - && (rs.getInt("pk") == 0)) - schemaResultCheck[4] = true; - //System.out.println("Got 4"); - break; - case 5: - if (rs.getString("name").equals("object") - && rs.getString("type").equals("TEXT") - && (rs.getInt("notnull") == 0) - && (rs.getString("dflt_value") == null) - && (rs.getInt("pk") == 0)) - schemaResultCheck[5] = true; - //System.out.println("Got 5"); - break; - default: - for (int i = 0; i <= 5; i++) { - schemaResultCheck[i] = false; // If more then 5 elements, ruin results - } - } - } - // Validating result: it table in DB have expected schema. If not, removing and recreating table. - for (boolean element: schemaResultCheck) { - if (!element) { - System.out.println("BotSQLiteWorker (@"+server+")->Constructor(): Notice:\n\tFound already existing table for channel with incorrect syntax: removing table and re-creating."); - statement.executeUpdate("DROP TABLE \"" + channel + "\";"); - statement.executeUpdate(query); + // Check table representation + ResultSet rs = statement.executeQuery("PRAGMA table_info(\""+channel+"\");"); // executeQuery never null + boolean[] schemaResultCheck = {false, false, false, false, false, false}; + + while (rs.next()) { + switch (rs.getInt("cid")) { + case 0: + if (rs.getString("name").equals("id") + && rs.getString("type").equals("INTEGER") + && (rs.getInt("notnull") == 1) + && (rs.getString("dflt_value") == null) + && (rs.getInt("pk") == 1)) + schemaResultCheck[0] = true; + //System.out.println("Got 0"); break; - } + case 1: + if (rs.getString("name").equals("unixtime") + && rs.getString("type").equals("INTEGER") + && (rs.getInt("notnull") == 0) + && (rs.getString("dflt_value") == null) + && (rs.getInt("pk") == 0)) + schemaResultCheck[1] = true; + //System.out.println("Got 1"); + break; + case 2: + if (rs.getString("name").equals("event") + && rs.getString("type").equals("TEXT") + && (rs.getInt("notnull") == 0) + && (rs.getString("dflt_value") == null) + && (rs.getInt("pk") == 0)) + schemaResultCheck[2] = true; + //System.out.println("Got 2"); + break; + case 3: + if (rs.getString("name").equals("subject") + && rs.getString("type").equals("TEXT") + && (rs.getInt("notnull") == 0) + && (rs.getString("dflt_value") == null) + && (rs.getInt("pk") == 0)) + schemaResultCheck[3] = true; + //System.out.println("Got 3"); + break; + case 4: + if (rs.getString("name").equals("message") + && rs.getString("type").equals("TEXT") + && (rs.getInt("notnull") == 0) + && (rs.getString("dflt_value") == null) + && (rs.getInt("pk") == 0)) + schemaResultCheck[4] = true; + //System.out.println("Got 4"); + break; + case 5: + if (rs.getString("name").equals("object") + && rs.getString("type").equals("TEXT") + && (rs.getInt("notnull") == 0) + && (rs.getString("dflt_value") == null) + && (rs.getInt("pk") == 0)) + schemaResultCheck[5] = true; + //System.out.println("Got 5"); + break; + default: + for (int i = 0; i <= 5; i++) { + schemaResultCheck[i] = false; // If more then 5 elements, ruin results + } } - this.consistent = true; + } + // Validating result: it table in DB have expected schema. If not, removing and recreating table. + for (boolean element: schemaResultCheck) { + if (!element) { + System.out.println("BotSQLiteWorker (@"+server+")->Constructor(): Notice:\n\tFound already existing table for channel with incorrect syntax: removing table and re-creating."); + statement.executeUpdate("DROP TABLE \"" + channel + "\";"); + statement.executeUpdate(query); + break; + } + } + this.consistent = true; - this.preparedStatement = connection.prepareStatement( - "INSERT INTO \""+channel - +"\" (unixtime, event, subject, message, object) " - +"VALUES (?, ?, ?, ?, ?);"); - } - else { - System.out.println("BotSQLiteWorker (@"+server+")->constructor() failed:\n\t Connection to SQLite not established."); - this.consistent = false; - } + this.preparedStatement = connection.prepareStatement( + "INSERT INTO \""+channel + +"\" (unixtime, event, subject, message, object) " + +"VALUES (?, ?, ?, ?, ?);"); } - catch (SQLException e){ - System.out.println("BotSQLiteWorker (@"+server+")->constructor() failed:\n\t"+e); - this.consistent = false; // this.close(); + else { + System.out.println("BotSQLiteWorker (@"+server+")->constructor() failed:\n\t Connection to SQLite not established."); + this.consistent = false; } } @@ -161,11 +152,6 @@ public class WorkerSQLite implements Worker { preparedStatement.setString(2, event); preparedStatement.setString(3, initiator); switch (event) { - case "NICK": - case "JOIN": - preparedStatement.setString(4, message); - preparedStatement.setString(5, null); - break; case "PART": case "QUIT": case "TOPIC": @@ -184,6 +170,8 @@ public class WorkerSQLite implements Worker { preparedStatement.setString(4, message.replaceAll("^:", "")); preparedStatement.setString(5,null); break; + case "NICK": + case "JOIN": default: preparedStatement.setString(4, message); preparedStatement.setString(5,null); @@ -191,12 +179,9 @@ public class WorkerSQLite implements Worker { } preparedStatement.executeUpdate(); } - catch (SQLException sqle){ - System.out.println("BotSQLiteWorker (@"+ircServer+")->logAdd() failed:\n\t"+sqle); - this.close(); // consistent will become false. Don't touch this. - }catch (NullPointerException npe){ - System.out.println("BotSQLiteWorker (@"+ircServer+")->logAdd() failed:\n\t"+npe); - this.consistent = false; // most likely closed/non-opened file + catch (Exception e) { + System.out.println("BotSQLiteWorker (@" + server + ")->logAdd() failed:\n\t" + e.getMessage()); + this.close(); } return consistent; } @@ -208,7 +193,7 @@ public class WorkerSQLite implements Worker { this.connection.close(); } catch (SQLException | NullPointerException e){ //todo: consider redo - System.out.println("BotSQLiteWorker (@"+ircServer+")->close() failed:\n\t" + e); // nothing to do here + System.out.println("BotSQLiteWorker (@"+ server +")->close() failed:\n\t" + e); // nothing to do here } this.consistent = false; } diff --git a/src/test/java/InnaIrcBot/config/ConfigurationFileTest.java b/src/test/java/InnaIrcBot/config/ConfigurationFileTest.java index f496120..57a9b2f 100644 --- a/src/test/java/InnaIrcBot/config/ConfigurationFileTest.java +++ b/src/test/java/InnaIrcBot/config/ConfigurationFileTest.java @@ -1,38 +1,86 @@ package InnaIrcBot.config; import InnaIrcBot.logging.SupportedLogDrivers; +import org.ini4j.Config; +import org.ini4j.Ini; +import org.ini4j.Wini; import org.junit.jupiter.api.Test; +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + import static org.junit.jupiter.api.Assertions.*; class ConfigurationFileTest { ConfigurationFile config; - ConfigurationFileTest(){ - config = new ConfigurationFile( - null, - -100, - null, - null, - null, - null, - null, - null, - null, - null, - true, - null, - new String[]{null}, - null, - null, - null - ); + ConfigurationFileTest() throws Exception{ + File file = File.createTempFile("temp", "Ini"); +/* + List logDriverPreferences = new ArrayList<>(); + logDriverPreferences.add(System.getProperty("user.home")); + + List channels = new ArrayList<>(); + channels.add("#main"); + channels.add("#lpr"); + + Config myConfig = new Config(); + myConfig.setFileEncoding(StandardCharsets.UTF_8); + + Wini ini = new Wini(); + ini.setConfig(myConfig); + + Ini.Section mainSection = ini.add("main"); + mainSection.put( "server name", "srv"); + mainSection.put( "server port", 6667); + mainSection.put( "server password", ""); + mainSection.put( "channels", channels); //mainSectionName, + mainSection.put( "nickname", "InnaIrcBot"); + mainSection.put( "ident", "sweethome"); + mainSection.put( "real name", "bot"); + mainSection.put( "nickname password", ""); + mainSection.put( "nickserv auth method", "freenode"); + mainSection.put( "user modes", "i"); + mainSection.put( "auto rejoin", true); + mainSection.put( "logging driver", "files"); + mainSection.put( "logging driver prefs", logDriverPreferences); + mainSection.put( "bot administrator password", "i_pswd"); + mainSection.put( "channels configuration path", "/tmp"); + mainSection.put( "application logs", "/tmp"); + ini.store(file); + + */ + ConfigurationFileGenerator.generate(file.getAbsolutePath()); + config = new ConfigurationFile(file.getAbsolutePath()); + printAllConfigFields(); + } + + private String generateFile(){ + return ""; + } + + private void printAllConfigFields(){ + System.out.println(); + System.out.println(config.getServerName());; + System.out.println(config.getServerPort());; + System.out.println(config.getServerPass());; + System.out.println(config.getUserNick());; + System.out.println(config.getUserIdent());; + System.out.println(config.getUserRealName());; + System.out.println(config.getUserNickPass());; + System.out.println(config.getUserNickAuthStyle());; + System.out.println(config.getUserMode());; + System.out.println(config.getRejoinOnKick());; + System.out.println(config.getBotAdministratorPassword());; + System.out.println(config.getApplicationLogDir());; } @Test void getServerName() { } - +/* @Test void getServerPort() { } @@ -93,4 +141,5 @@ class ConfigurationFileTest { @Test void setUserNickAuthStyle() { } + */ } \ No newline at end of file diff --git a/src/test/java/InnaIrcBot/logging/LogDriverTest.java b/src/test/java/InnaIrcBot/logging/LogDriverTest.java index 8a563de..baf703f 100644 --- a/src/test/java/InnaIrcBot/logging/LogDriverTest.java +++ b/src/test/java/InnaIrcBot/logging/LogDriverTest.java @@ -110,20 +110,34 @@ class LogDriverTest { } private void initializeFilesLogDriver(){ - LogDriver.setLogDriver(serverNameFiles, new LogDriverConfiguration("FileS", new String[]{mainLogsDir.toString()}), ""); + LogDriverConfiguration filesDrv = new LogDriverConfiguration("FileS", + mainLogsDir.toString(), + null, + null, + null, + null); + LogDriver.setLogDriver(serverNameFiles); } private void initializeSQLiteLogDriver(){ - LogDriver.setLogDriver(serverNameSQLite, new LogDriverConfiguration("SQliTe", new String[]{mainSQLiteLogsDir.toString()}), ""); + LogDriverConfiguration sqliteDrv = new LogDriverConfiguration("SQliTe", + mainLogsDir.toString(), + null, + null, + null, + null); + + LogDriver.setLogDriver(serverNameSQLite); } private void initializeMongoDBLogDriver(){ - String[] params = new String[]{"192.168.1.186:27017", - "irc", - "loper", - "password"}; - - LogDriver.setLogDriver("irc.tomsk.net",new LogDriverConfiguration("MongoDB", params),""); + LogDriverConfiguration mongoDrv = new LogDriverConfiguration("MongoDB", + null, + "192.168.1.186:27017", + "irc", + "loper", + "password"); + LogDriver.setLogDriver("irc.tomsk.net"); } private void close(){