From 434e7e3715c515f760c997c40b6c1b91f3adabb6 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Thu, 17 Jan 2019 04:47:35 +0300 Subject: [PATCH 1/6] v0.4 drafts --- pom.xml | 8 +- src/main/java/InnaIrcBot/BotStart.java | 1 + .../Commanders/PrivateMsgCommander.java | 2 +- src/main/java/InnaIrcBot/GlobalData.java | 2 +- .../java/InnaIrcBot/LogDriver/BotDriver.java | 2 + .../InnaIrcBot/LogDriver/BotMongoWorker.java | 147 ++++++++++++++++++ .../InnaIrcBot/LogDriver/BotSQLiteWorker.java | 8 +- .../ProvidersConsumers/SystemConsumer.java | 2 +- src/main/java/Temporary/DriverTest.java | 36 +++-- .../java/Temporary/ReconnectControlTest.java | 2 +- 10 files changed, 189 insertions(+), 21 deletions(-) create mode 100644 src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java diff --git a/pom.xml b/pom.xml index d056808..4ef9c4e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 loper InnaIrcBot - 0.3-SNAPSHOT + 0.4-SNAPSHOT jar InnaIrcBot @@ -24,6 +24,12 @@ 2.8.5 compile + + org.mongodb + mongodb-driver-sync + 3.9.1 + compile + diff --git a/src/main/java/InnaIrcBot/BotStart.java b/src/main/java/InnaIrcBot/BotStart.java index 26ebf64..8f9bcb7 100644 --- a/src/main/java/InnaIrcBot/BotStart.java +++ b/src/main/java/InnaIrcBot/BotStart.java @@ -11,6 +11,7 @@ public class BotStart { //TODO: flood control //TODO: setDaemon(true) //TODO: multiple connections to one server not allowed + // TODO switch to zero-worker in case of inconsistent state of Worker public static void main(String[] args){ if (args.length != 0) { diff --git a/src/main/java/InnaIrcBot/Commanders/PrivateMsgCommander.java b/src/main/java/InnaIrcBot/Commanders/PrivateMsgCommander.java index fa650e6..137f643 100644 --- a/src/main/java/InnaIrcBot/Commanders/PrivateMsgCommander.java +++ b/src/main/java/InnaIrcBot/Commanders/PrivateMsgCommander.java @@ -290,7 +290,7 @@ public class PrivateMsgCommander { // T } } private void kickban(String chanel, String user, String reason){ - cmode(chanel, "+b", simplifyNick(user)+"*!*@*"); + ban(chanel, user); kick(chanel, user, reason); } private void voice(String chanel, String user){ diff --git a/src/main/java/InnaIrcBot/GlobalData.java b/src/main/java/InnaIrcBot/GlobalData.java index 4de2d8a..55f9691 100644 --- a/src/main/java/InnaIrcBot/GlobalData.java +++ b/src/main/java/InnaIrcBot/GlobalData.java @@ -1,7 +1,7 @@ package InnaIrcBot; public class GlobalData { - private static final String version = "InnaIrcBot v0.3 \"Карелия\""; + private static final String version = "InnaIrcBot v0.4 \"Карские Ворота\""; public static synchronized String getAppVersion(){ return version; } diff --git a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java index faedb96..cc272a1 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java @@ -27,6 +27,8 @@ public class BotDriver { return new BotFilesWorker(serverName, serverDriver.get(serverName)[1], chanelName); case "SQLite": return new BotSQLiteWorker(serverName, serverDriver.get(serverName)[1], chanelName); + case "MongoDB": + return new BotMongoWorker(serverName, serverDriver.get(serverName)[1], chanelName); case "Zero": return new BotZeroWorker(); default: diff --git a/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java new file mode 100644 index 0000000..f456f94 --- /dev/null +++ b/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java @@ -0,0 +1,147 @@ +package InnaIrcBot.LogDriver; + + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.MongoTimeoutException; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.event.*; +import org.bson.Document; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +/** For each IRC server we create one DB that stored in the hashmap ('static', since we may have few configuration that have to work at once) + * For each channel we store collection that have name of the ircServer + chanelName. + * If user decides to use one MongoDB for various servers, he may use even one DB (declared in configuration file) and store collections in there. + * **/ +public class BotMongoWorker implements Worker { + + private static Map serversMap = Collections.synchronizedMap(new HashMap()); + + private String ircServer; + private MongoCollection collection; + private boolean consistent = true; // TODO: clarify possible issues??? + + public BotMongoWorker(String ircServer, String[] driverParameters, String channel){ + if (channel.equals("system")) // Set ircServer variable only if it's 'system' log thread. + this.ircServer = ircServer; + else + this.ircServer = null; + + if (!serversMap.containsKey(ircServer)){ + + MongoClientSettings MCS = MongoClientSettings.builder().addCommandListener(new CommandListener() { + @Override + public void commandStarted(CommandStartedEvent commandStartedEvent) { + System.out.println("commandStarted"); + } + + @Override + public void commandSucceeded(CommandSucceededEvent commandSucceededEvent) { + System.out.println("commandSucceeded"); + } + + @Override + public void commandFailed(CommandFailedEvent commandFailedEvent) { + System.out.println("commandFailed"); + } + }) + .applyConnectionString(new ConnectionString("mongodb://asasa:27017")) + .applyToServerSettings(builder -> builder.addServerListener(new ServerListener() { + @Override + public void serverOpening(ServerOpeningEvent serverOpeningEvent) { + System.out.println("Server Listener: 1 SRV ID: "+serverOpeningEvent.getServerId()); + } + + @Override + public void serverClosed(ServerClosedEvent serverClosedEvent) { + System.out.println("Server Listener: Server has been closed"); + } + + @Override + public void serverDescriptionChanged(ServerDescriptionChangedEvent serverDescriptionChangedEvent) { + System.out.println("Server Listener: Desc Changed: "+serverDescriptionChangedEvent.getNewDescription().getException()); + close(); + } + })) + .build(); + + MongoClient mongoClient = MongoClients.create(MCS); + //MongoClient mongoClient = MongoClients.create("mongodb://asasa:27017"); // TODO: replace with driverParameters[0] - address + serversMap.put(ircServer, mongoClient); + } + + MongoDatabase mongoDB = serversMap.get(ircServer).getDatabase("irc"); // TODO: replace with driverParameters[1] - DB NAME + collection = mongoDB.getCollection(ircServer + channel); + + Document ping = new Document("ping", "1"); + try { + collection.insertOne(ping); + }catch (MongoTimeoutException e) { + System.out.println("Timeout exception"); + consistent = false; + } catch (IllegalStateException ise){ + System.out.println("Illegal state exception: MongoDB server already closed."); + consistent = false; + } + + } + + @Override + public void logAdd(String event, String initiatorArg, String messageArg) { + Document document = new Document("date", getDate()) + .append("event", event) + .append("initiator", initiatorArg); + switch (event) { + case "NICK": + case "JOIN": + document.append("message1", messageArg); + //preparedStatement.setString(5, null); + break; + case "PART": + case "QUIT": + case "TOPIC": + document.append("message1", messageArg.replaceAll("^.+?:", "")); + //preparedStatement.setString(5, null); + break; + case "MODE": + document.append("message1", messageArg.replaceAll("(^(.+?\\s){1})|(\\s.+$)","")); + document.append("message2", messageArg.replaceAll("^(.+?\\s){2}", "")); + break; + case "KICK": + document.append("message1", messageArg.replaceAll("^.+?:", "")); + document.append("message2", messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")); + break; + case "PRIVMSG": + document.append("message1", messageArg.replaceAll("^:", "")); + //preparedStatement.setString(5,null); + break; + default: + document.append("message1", messageArg); + //preparedStatement.setString(5,null); + break; + } + collection.insertOne(document); + } + + private long getDate(){ return System.currentTimeMillis() / 1000L; } // UNIX time + + @Override + public boolean isConsistent() { return consistent; } + + @Override + public void close() { + // If ircServer != null then it's system thread and when it's interrupted we have to close connection to DB for used server + // And remove it from HashMap + if (this.ircServer != null && serversMap.containsKey(ircServer)) { + serversMap.get(ircServer).close(); + serversMap.remove(ircServer); + System.out.println("BotMongoWorker->close(): " + ircServer); + } + + } +} diff --git a/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java index a47a955..199e851 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java @@ -168,15 +168,15 @@ public class BotSQLiteWorker implements Worker { preparedStatement.setString(5, messageArg.replaceAll("^(.+?\\s){2}", "")); break; case "KICK": - preparedStatement.setString(4,messageArg.replaceAll("^.+?:", "")); - preparedStatement.setString(5,messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")); + preparedStatement.setString(4, messageArg.replaceAll("^.+?:", "")); + preparedStatement.setString(5, messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")); break; case "PRIVMSG": - preparedStatement.setString(4,messageArg.replaceAll("^:", "")); + preparedStatement.setString(4, messageArg.replaceAll("^:", "")); preparedStatement.setString(5,null); break; default: - preparedStatement.setString(4,messageArg); + preparedStatement.setString(4, messageArg); preparedStatement.setString(5,null); break; } diff --git a/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java b/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java index e452f9b..8609a2d 100644 --- a/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java +++ b/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java @@ -65,7 +65,7 @@ public class SystemConsumer implements Runnable{ private void setMainRoutine(){ String data; - String dataStrings[]; + String[] dataStrings; try { while ((data = reader.readLine()) != null) { dataStrings = data.split(" ",3); diff --git a/src/main/java/Temporary/DriverTest.java b/src/main/java/Temporary/DriverTest.java index 14b484d..9783ea4 100644 --- a/src/main/java/Temporary/DriverTest.java +++ b/src/main/java/Temporary/DriverTest.java @@ -6,34 +6,46 @@ import InnaIrcBot.LogDriver.Worker; public class DriverTest { public static void main(String[] args){ - if (BotDriver.setLogDriver("irc.tomsk.net", "SQLiteDriver", new String[]{"/tmp/"})) + if (BotDriver.setLogDriver("irc.tomsk.net", "MongoDB", new String[]{"/tmp/"})) System.out.println("Successful driver initiation"); else { System.out.println("Failed driver initiation"); return; } - Worker fw1 = BotDriver.getWorker("irc.tomsk.net","#lpr"); - Worker fw2 = BotDriver.getWorker("irc.tomsk.net","#main"); - Worker fw3 = BotDriver.getWorker("irc.tomsk.net","##loper"); + Worker fw1 = BotDriver.getWorker("irc.tomsk.net","system"); + //Worker fw2 = BotDriver.getWorker("irc.tomsk.net","#main"); + //Worker fw3 = BotDriver.getWorker("irc.tomsk.net","#lpr"); - if ((fw1 !=null) && (fw2 !=null) && (fw3 !=null)){ + //if ((fw1 !=null) && (fw2 !=null) && (fw3 !=null)){ System.out.println("LogFile1: "+fw1.isConsistent()); - System.out.println("LogFile2: "+fw2.isConsistent()); - System.out.println("LogFile3: "+fw3.isConsistent()); - + //System.out.println("LogFile2: "+fw2.isConsistent()); + //System.out.println("LogFile3: "+fw3.isConsistent()); +/* fw1.logAdd("JOIN", "de_su!loper@desktop.lan", "message1"); + fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + fw1.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + fw1.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); fw1.logAdd("PART", "de_su!loper@desktop.lan", "#chan1"); fw2.logAdd("JOIN", "de_su!loper@desktop.lan", "message2"); + fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + fw2.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + fw2.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); fw2.logAdd("PART", "de_su!loper@desktop.lan", "#chan2"); fw3.logAdd("JOIN", "de_su!loper@desktop.lan", "message3"); + fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + fw3.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + fw3.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); fw3.logAdd("PART", "de_su!loper@desktop.lan", "#chan3"); - +*/ fw1.close(); - fw2.close(); - fw3.close(); - } + //fw2.close(); + //fw3.close(); + //} } } diff --git a/src/main/java/Temporary/ReconnectControlTest.java b/src/main/java/Temporary/ReconnectControlTest.java index 9330684..ab2ff90 100644 --- a/src/main/java/Temporary/ReconnectControlTest.java +++ b/src/main/java/Temporary/ReconnectControlTest.java @@ -3,7 +3,7 @@ package Temporary; import InnaIrcBot.ReconnectControl; public class ReconnectControlTest { - public static void main(String args[]){ + public static void main(String[] args){ ReconnectControl.register("testing"); ReconnectControl.register("testing1"); ReconnectControl.update("testing1", false); From 7ed9d8615e05dd335895df21e1c41ef9a8f6a831 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Fri, 18 Jan 2019 05:34:08 +0300 Subject: [PATCH 2/6] v0.4 more drafts --- README.md | 2 +- .../java/InnaIrcBot/LogDriver/BotDriver.java | 6 +- .../InnaIrcBot/LogDriver/BotMongoWorker.java | 74 +++++++++++-------- .../ProvidersConsumers/SystemConsumer.java | 2 +- src/main/java/Temporary/DriverTest.java | 12 +-- 5 files changed, 58 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 9e8a830..40d0c99 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Used libraries: - [x] CI/CD Jenkins - [ ] Suppress messages from server or handle them separately from selected worker - [ ] Logs backend workers as threads (SQLite and co. are too slow) -- [ ] Logs backend worker for mongodb +- [x] Logs backend worker for mongodb - [ ] Logs backend worker for redis/redis node - [ ] Re-implement connection routine - [ ] Availability to run scripts @ 'ChanelCommander' diff --git a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java index cc272a1..bec8f4f 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java @@ -28,7 +28,11 @@ public class BotDriver { case "SQLite": return new BotSQLiteWorker(serverName, serverDriver.get(serverName)[1], chanelName); case "MongoDB": - return new BotMongoWorker(serverName, serverDriver.get(serverName)[1], chanelName); + BotMongoWorker botMongoWorker = new BotMongoWorker(serverName, serverDriver.get(serverName)[1], chanelName); + if (botMongoWorker.isConsistent()) + return botMongoWorker; + else + System.out.println("BotDriver: Unable to use MongoWorker. Using ZeroWorker instead."); // else, fall down and use BotZeroWorker. case "Zero": return new BotZeroWorker(); default: diff --git a/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java index f456f94..f70e87d 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java @@ -1,6 +1,5 @@ package InnaIrcBot.LogDriver; - import com.mongodb.ConnectionString; import com.mongodb.MongoClientSettings; import com.mongodb.MongoTimeoutException; @@ -24,7 +23,7 @@ public class BotMongoWorker implements Worker { private String ircServer; private MongoCollection collection; - private boolean consistent = true; // TODO: clarify possible issues??? + private boolean consistent = false; // TODO: clarify possible issues??? public BotMongoWorker(String ircServer, String[] driverParameters, String channel){ if (channel.equals("system")) // Set ircServer variable only if it's 'system' log thread. @@ -34,44 +33,54 @@ public class BotMongoWorker implements Worker { if (!serversMap.containsKey(ircServer)){ - MongoClientSettings MCS = MongoClientSettings.builder().addCommandListener(new CommandListener() { + CommandListener mongoCommandListener = new CommandListener() { @Override public void commandStarted(CommandStartedEvent commandStartedEvent) { - System.out.println("commandStarted"); + System.out.println("C: commandStarted"); } @Override public void commandSucceeded(CommandSucceededEvent commandSucceededEvent) { - System.out.println("commandSucceeded"); + System.out.println("C: commandSucceeded"); } @Override public void commandFailed(CommandFailedEvent commandFailedEvent) { - System.out.println("commandFailed"); + System.out.println("C: commandFailed"); + consistent = false; + close(ircServer); // ircServer recieved by constructor, not this.ircServer } - }) - .applyConnectionString(new ConnectionString("mongodb://asasa:27017")) - .applyToServerSettings(builder -> builder.addServerListener(new ServerListener() { - @Override - public void serverOpening(ServerOpeningEvent serverOpeningEvent) { - System.out.println("Server Listener: 1 SRV ID: "+serverOpeningEvent.getServerId()); - } + }; - @Override - public void serverClosed(ServerClosedEvent serverClosedEvent) { - System.out.println("Server Listener: Server has been closed"); - } + ServerListener mongoServerListener = new ServerListener() { + @Override + public void serverOpening(ServerOpeningEvent serverOpeningEvent) { + System.out.println("BotMongoWorker: ServerListener: Server opened successfully: "+serverOpeningEvent.getServerId()); + } - @Override - public void serverDescriptionChanged(ServerDescriptionChangedEvent serverDescriptionChangedEvent) { - System.out.println("Server Listener: Desc Changed: "+serverDescriptionChangedEvent.getNewDescription().getException()); - close(); - } - })) + @Override + public void serverClosed(ServerClosedEvent serverClosedEvent) { + System.out.println("BotMongoWorker: ServerListener: Server has been closed"); + } + + @Override + public void serverDescriptionChanged(ServerDescriptionChangedEvent serverDescriptionChangedEvent) { + if (!serverDescriptionChangedEvent.getNewDescription().isOk()) { + consistent = false; + close(ircServer); // ircServer recieved by constructor, not this.ircServer + System.out.println("BotMongoWorker: ServerListener: Server description changed (exception occurs): " + + serverDescriptionChangedEvent.getNewDescription().getException()); + } + } + }; + + MongoClientSettings MCS = MongoClientSettings.builder() + .addCommandListener(mongoCommandListener) + .applyConnectionString(new ConnectionString("mongodb://192.168.1.186:27017")) // TODO: replace with driverParameters[0] - address + .applyToServerSettings(builder -> builder.addServerListener(mongoServerListener)) .build(); MongoClient mongoClient = MongoClients.create(MCS); - //MongoClient mongoClient = MongoClients.create("mongodb://asasa:27017"); // TODO: replace with driverParameters[0] - address serversMap.put(ircServer, mongoClient); } @@ -81,14 +90,15 @@ public class BotMongoWorker implements Worker { Document ping = new Document("ping", "1"); try { collection.insertOne(ping); - }catch (MongoTimeoutException e) { - System.out.println("Timeout exception"); + consistent = true; // if no exceptions, then true + } catch (MongoTimeoutException e) { + System.out.println("BotMongoWorker: Timeout exception"); consistent = false; + close(ircServer); // ircServer recieved by constructor, not this.ircServer } catch (IllegalStateException ise){ - System.out.println("Illegal state exception: MongoDB server already closed."); + System.out.println("BotMongoWorker: Illegal state exception: MongoDB server already closed (not an issue)."); consistent = false; } - } @Override @@ -142,6 +152,12 @@ public class BotMongoWorker implements Worker { serversMap.remove(ircServer); System.out.println("BotMongoWorker->close(): " + ircServer); } - + } + public void close(String server) { + if (serversMap.containsKey(server)) { + serversMap.get(server).close(); + serversMap.remove(server); + System.out.println("BotMongoWorker->close(): " + server + " (forced by listeners)"); + } } } diff --git a/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java b/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java index 8609a2d..4689807 100644 --- a/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java +++ b/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java @@ -197,7 +197,7 @@ public class SystemConsumer implements Runnable{ } } else - System.out.println("Some internal shit happens that shouldn't happens never ever. Take your cat, call scientists and wait for singularity. Panic allowed."); + System.out.println("Some internal shit happens that shouldn't happens never ever. Take your cat, call scientists and wait for singularity. Panic allowed. Log: \nEvent:|"+eventNum+"| sender:|"+sender+"| message|"+message+"|"); break; case "NICK": if (sender.startsWith(nick+"!")) { diff --git a/src/main/java/Temporary/DriverTest.java b/src/main/java/Temporary/DriverTest.java index 9783ea4..23361b4 100644 --- a/src/main/java/Temporary/DriverTest.java +++ b/src/main/java/Temporary/DriverTest.java @@ -14,13 +14,13 @@ public class DriverTest { } Worker fw1 = BotDriver.getWorker("irc.tomsk.net","system"); - //Worker fw2 = BotDriver.getWorker("irc.tomsk.net","#main"); - //Worker fw3 = BotDriver.getWorker("irc.tomsk.net","#lpr"); + Worker fw2 = BotDriver.getWorker("irc.tomsk.net","#main"); + Worker fw3 = BotDriver.getWorker("irc.tomsk.net","#lpr"); //if ((fw1 !=null) && (fw2 !=null) && (fw3 !=null)){ System.out.println("LogFile1: "+fw1.isConsistent()); - //System.out.println("LogFile2: "+fw2.isConsistent()); - //System.out.println("LogFile3: "+fw3.isConsistent()); + System.out.println("LogFile2: "+fw2.isConsistent()); + System.out.println("LogFile3: "+fw3.isConsistent()); /* fw1.logAdd("JOIN", "de_su!loper@desktop.lan", "message1"); fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); @@ -44,8 +44,8 @@ public class DriverTest { fw3.logAdd("PART", "de_su!loper@desktop.lan", "#chan3"); */ fw1.close(); - //fw2.close(); - //fw3.close(); + fw2.close(); + fw3.close(); //} } } From c8ab5a096494fda82b728a85378db3ff6d95a542 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Tue, 22 Jan 2019 05:31:43 +0300 Subject: [PATCH 3/6] v0.4 moar --- README.md | 5 +- .../Commanders/ChanelCommander.java | 9 +- .../java/InnaIrcBot/LogDriver/BotDriver.java | 2 +- .../InnaIrcBot/LogDriver/BotMongoWorker.java | 82 +++++++++++++------ .../InnaIrcBot/LogDriver/BotSQLiteWorker.java | 4 +- src/main/java/Temporary/DriverTest.java | 13 +-- 6 files changed, 78 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 40d0c99..6582a4a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # InnaIrcBot -Another one IRC bot in deep beta. +Another one IRC bot in deep-deep beta. ## Usage ` -c, --configuration [ ...] Read Config` @@ -41,3 +41,6 @@ Used libraries: - [ ] Deep configuration files validation - [x] Maven ~~or Gradle~~ build - [ ] ncurses-like or/and GUI configuration files (server/chanel setting) editor +- [ ] CTCP support for using @ 'ChanelCommander' +- [ ] Access roles support (i.e. delegating some rights to another users) +- [ ] Logs for application \ No newline at end of file diff --git a/src/main/java/InnaIrcBot/Commanders/ChanelCommander.java b/src/main/java/InnaIrcBot/Commanders/ChanelCommander.java index fa56643..8d2e7c7 100644 --- a/src/main/java/InnaIrcBot/Commanders/ChanelCommander.java +++ b/src/main/java/InnaIrcBot/Commanders/ChanelCommander.java @@ -132,7 +132,11 @@ public class ChanelCommander implements Runnable { for (i++; (i < cmdOrMsg.length) && !(cmdOrMsg[i].startsWith("\\")); i++) whatToSendRaw.append(cmdOrMsg[i]); StreamProvider.writeToStream(server, whatToSendRaw.toString()); //TODO - break; //todo: add script + break; //todo: add script + case "\\whois": // result will be noted in 'system' log + whoisAction(arg2); + i++; + break; default: i++; } @@ -140,6 +144,9 @@ public class ChanelCommander implements Runnable { } } ///////// ///////// + private void whoisAction(String who){ // TODO: maybe we have to extend functionality to reuse received information. + StreamProvider.writeToStream(server, "WHOIS "+simplifyNick(who)); + } private void msgAction(String[] messages, String who, boolean sendToPrivate){ StringBuilder executiveStr = new StringBuilder(); executiveStr.append("PRIVMSG "); diff --git a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java index bec8f4f..dd62830 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java @@ -32,7 +32,7 @@ public class BotDriver { if (botMongoWorker.isConsistent()) return botMongoWorker; else - System.out.println("BotDriver: Unable to use MongoWorker. Using ZeroWorker instead."); // else, fall down and use BotZeroWorker. + System.out.println("BotDriver: Unable to use MongoWorker for "+serverName+". Using ZeroWorker instead."); // else, fall down and use BotZeroWorker. case "Zero": return new BotZeroWorker(); default: diff --git a/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java index f70e87d..ea20cbb 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java @@ -1,8 +1,6 @@ package InnaIrcBot.LogDriver; -import com.mongodb.ConnectionString; -import com.mongodb.MongoClientSettings; -import com.mongodb.MongoTimeoutException; +import com.mongodb.*; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; import com.mongodb.client.MongoCollection; @@ -25,42 +23,63 @@ public class BotMongoWorker implements Worker { private MongoCollection collection; private boolean consistent = false; // TODO: clarify possible issues??? + private boolean isItSystemThread = false; + public BotMongoWorker(String ircServer, String[] driverParameters, String channel){ - if (channel.equals("system")) // Set ircServer variable only if it's 'system' log thread. - this.ircServer = ircServer; + this.ircServer = ircServer; + + String mongoHostAddr; + String mongoDBName; + String mongoUser; + String mongoPass; + if (driverParameters.length >= 2 && !driverParameters[0].isEmpty() && !driverParameters[1].isEmpty()) { + mongoHostAddr = driverParameters[0]; + mongoDBName = driverParameters[1]; + 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 ;) + mongoUser = "anon"; + mongoPass = "anon"; + } + } else - this.ircServer = null; + return; // consistent = false + + if (channel.equals("system")) // Set ircServer variable only if it's 'system' log thread. + this.isItSystemThread = true; if (!serversMap.containsKey(ircServer)){ - + /* // Leave this validations for better times. CommandListener mongoCommandListener = new CommandListener() { @Override public void commandStarted(CommandStartedEvent commandStartedEvent) { - System.out.println("C: commandStarted"); + System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandStarted"); } @Override public void commandSucceeded(CommandSucceededEvent commandSucceededEvent) { - System.out.println("C: commandSucceeded"); + System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandSucceeded"); } @Override public void commandFailed(CommandFailedEvent commandFailedEvent) { - System.out.println("C: commandFailed"); - consistent = false; - close(ircServer); // ircServer recieved by constructor, not this.ircServer + System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandFailed"); + //consistent = false; + //close(ircServer); // ircServer recieved by constructor, not this.ircServer } }; - + */ ServerListener mongoServerListener = new ServerListener() { @Override public void serverOpening(ServerOpeningEvent serverOpeningEvent) { - System.out.println("BotMongoWorker: ServerListener: Server opened successfully: "+serverOpeningEvent.getServerId()); + System.out.println("BotMongoWorker (@"+ircServer+"): ServerListener: Server opened successfully: "+serverOpeningEvent.getServerId()); } @Override public void serverClosed(ServerClosedEvent serverClosedEvent) { - System.out.println("BotMongoWorker: ServerListener: Server has been closed"); + System.out.println("BotMongoWorker (@"+ircServer+"): ServerListener: Server has been closed"); } @Override @@ -68,35 +87,44 @@ public class BotMongoWorker implements Worker { if (!serverDescriptionChangedEvent.getNewDescription().isOk()) { consistent = false; close(ircServer); // ircServer recieved by constructor, not this.ircServer - System.out.println("BotMongoWorker: ServerListener: Server description changed (exception occurs): " + System.out.println("BotMongoWorker (@"+ircServer+"): ServerListener: Server description changed (exception occurs): " + serverDescriptionChangedEvent.getNewDescription().getException()); } } }; MongoClientSettings MCS = MongoClientSettings.builder() - .addCommandListener(mongoCommandListener) - .applyConnectionString(new ConnectionString("mongodb://192.168.1.186:27017")) // TODO: replace with driverParameters[0] - address + // .addCommandListener(mongoCommandListener) + .applyConnectionString(new ConnectionString("mongodb://"+mongoHostAddr)) .applyToServerSettings(builder -> builder.addServerListener(mongoServerListener)) + .credential(MongoCredential.createCredential(mongoUser, mongoDBName, mongoPass.toCharArray())) .build(); MongoClient mongoClient = MongoClients.create(MCS); serversMap.put(ircServer, mongoClient); } - MongoDatabase mongoDB = serversMap.get(ircServer).getDatabase("irc"); // TODO: replace with driverParameters[1] - DB NAME + MongoDatabase mongoDB = serversMap.get(ircServer).getDatabase(mongoDBName); collection = mongoDB.getCollection(ircServer + channel); Document ping = new Document("ping", "1"); try { collection.insertOne(ping); consistent = true; // if no exceptions, then true - } catch (MongoTimeoutException e) { - System.out.println("BotMongoWorker: Timeout exception"); + } catch (MongoCommandException mce){ + System.out.println("BotMongoWorker (@"+this.ircServer+"): Command exception. Check if username/password set correctly."); consistent = false; - close(ircServer); // ircServer recieved by constructor, not this.ircServer + close(ircServer); // ircServer received by constructor, not this.ircServer + } catch (MongoTimeoutException mte) { + System.out.println("BotMongoWorker (@"+this.ircServer+"): Timeout exception"); + consistent = false; + close(ircServer); // ircServer received by constructor, not this.ircServer + }catch (MongoException me){ + System.out.println("BotMongoWorker (@"+this.ircServer+"): MongoDB Exception"); + consistent = false; + close(ircServer); // ircServer received by constructor, not this.ircServer } catch (IllegalStateException ise){ - System.out.println("BotMongoWorker: Illegal state exception: MongoDB server already closed (not an issue)."); + System.out.println("BotMongoWorker (@"+this.ircServer+"): Illegal state exception: MongoDB server already closed (not an issue)."); consistent = false; } } @@ -135,7 +163,7 @@ public class BotMongoWorker implements Worker { //preparedStatement.setString(5,null); break; } - collection.insertOne(document); + collection.insertOne(document); // TODO: try/catch and watch } private long getDate(){ return System.currentTimeMillis() / 1000L; } // UNIX time @@ -147,17 +175,17 @@ public class BotMongoWorker implements Worker { public void close() { // If ircServer != null then it's system thread and when it's interrupted we have to close connection to DB for used server // And remove it from HashMap - if (this.ircServer != null && serversMap.containsKey(ircServer)) { + if (this.isItSystemThread && serversMap.containsKey(ircServer)) { serversMap.get(ircServer).close(); serversMap.remove(ircServer); - System.out.println("BotMongoWorker->close(): " + ircServer); + System.out.println("BotMongoWorker (@"+this.ircServer+")->close(): " + ircServer); } } public void close(String server) { if (serversMap.containsKey(server)) { serversMap.get(server).close(); serversMap.remove(server); - System.out.println("BotMongoWorker->close(): " + server + " (forced by listeners)"); + System.out.println("BotMongoWorker (@"+this.ircServer+")->close(): " + server + " (forced by listeners)"); } } } diff --git a/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java index 199e851..183e08f 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java @@ -17,7 +17,7 @@ public class BotSQLiteWorker implements Worker { public BotSQLiteWorker(String server, String[] driverParameters, String channel){ // TODO: threads on SQLite level // remember: One file one DB driverParameters[0] = driverParameters[0].trim(); File dir = new File(driverParameters[0]); - dir.mkdirs(); + dir.mkdirs(); // TODO: Check if not-null if (!dir.exists()) { System.out.println("Unable to create directory to store DB file: " + driverParameters[0]); //TODO: notify requester this.consistent = false; @@ -116,7 +116,7 @@ public class BotSQLiteWorker implements Worker { // 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: Found already existing table for channel with incoorect syntax: removing table and re-creating."); + System.out.println("BotSQLiteWorker: Found already existing table for channel with incorrect syntax: removing table and re-creating."); statement.executeUpdate("DROP TABLE \"" + safeChanName + "\";"); statement.executeUpdate(query); break; diff --git a/src/main/java/Temporary/DriverTest.java b/src/main/java/Temporary/DriverTest.java index 23361b4..6b3e0be 100644 --- a/src/main/java/Temporary/DriverTest.java +++ b/src/main/java/Temporary/DriverTest.java @@ -6,7 +6,10 @@ import InnaIrcBot.LogDriver.Worker; public class DriverTest { public static void main(String[] args){ - if (BotDriver.setLogDriver("irc.tomsk.net", "MongoDB", new String[]{"/tmp/"})) + if (BotDriver.setLogDriver("irc.tomsk.net", "MongoDB", new String[]{"192.168.1.5:27017", + "irc", + "loper", + "password"})) System.out.println("Successful driver initiation"); else { System.out.println("Failed driver initiation"); @@ -17,11 +20,11 @@ public class DriverTest { Worker fw2 = BotDriver.getWorker("irc.tomsk.net","#main"); Worker fw3 = BotDriver.getWorker("irc.tomsk.net","#lpr"); - //if ((fw1 !=null) && (fw2 !=null) && (fw3 !=null)){ + if ((fw1 !=null) && (fw2 !=null) && (fw3 !=null)){ System.out.println("LogFile1: "+fw1.isConsistent()); System.out.println("LogFile2: "+fw2.isConsistent()); System.out.println("LogFile3: "+fw3.isConsistent()); -/* + fw1.logAdd("JOIN", "de_su!loper@desktop.lan", "message1"); fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); @@ -42,10 +45,10 @@ public class DriverTest { fw3.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); fw3.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); fw3.logAdd("PART", "de_su!loper@desktop.lan", "#chan3"); -*/ + fw1.close(); fw2.close(); fw3.close(); - //} + } } } From 9de9f8d36fdc5a736b017bcd2fb9af7f022b3131 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Fri, 25 Jan 2019 06:44:06 +0300 Subject: [PATCH 4/6] v0.4 stabilization --- README.md | 1 + .../java/InnaIrcBot/LogDriver/BotDriver.java | 30 +++-- .../InnaIrcBot/LogDriver/BotFilesWorker.java | 104 +++++++++++------- .../InnaIrcBot/LogDriver/BotMongoWorker.java | 57 +++++++--- .../InnaIrcBot/LogDriver/BotSQLiteWorker.java | 52 +++++---- .../InnaIrcBot/LogDriver/BotZeroWorker.java | 2 +- .../java/InnaIrcBot/LogDriver/Worker.java | 2 +- src/main/java/Temporary/DriverTest.java | 54 --------- src/main/java/Temporary/DriverTestFiles.java | 71 ++++++++++++ src/main/java/Temporary/DriverTestMongo.java | 73 ++++++++++++ src/main/java/Temporary/DriverTestSQLite.java | 70 ++++++++++++ 11 files changed, 371 insertions(+), 145 deletions(-) delete mode 100644 src/main/java/Temporary/DriverTest.java create mode 100644 src/main/java/Temporary/DriverTestFiles.java create mode 100644 src/main/java/Temporary/DriverTestMongo.java create mode 100644 src/main/java/Temporary/DriverTestSQLite.java diff --git a/README.md b/README.md index 6582a4a..255f7a0 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Source code spreads under the GNU General Public License v3 or higher. Please se Used libraries: * GSON: https://github.com/google/gson * sqliteJDBC: https://bitbucket.org/xerial/sqlite-jdbc +* mongodb-driver-sync: https://mongodb.github.io/mongo-java-driver/3.9/ ## TODO: diff --git a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java index dd62830..4099f46 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java @@ -22,18 +22,17 @@ public class BotDriver { } public static synchronized Worker getWorker(String serverName, String chanelName){ if (serverDriver.containsKey(serverName)) { - switch (serverDriver.get(serverName)[0][0]) { - case "Files": - return new BotFilesWorker(serverName, serverDriver.get(serverName)[1], chanelName); - case "SQLite": - return new BotSQLiteWorker(serverName, serverDriver.get(serverName)[1], chanelName); - case "MongoDB": + switch (serverDriver.get(serverName)[0][0].toLowerCase()) { + case "files": + BotFilesWorker botFilesWorker = new BotFilesWorker(serverName, serverDriver.get(serverName)[1], chanelName); + return validateConstancy(botFilesWorker, serverName, chanelName); + case "sqlite": + BotSQLiteWorker botSQLiteWorker = new BotSQLiteWorker(serverName, serverDriver.get(serverName)[1], chanelName); + return validateConstancy(botSQLiteWorker, serverName, chanelName); + case "mongodb": BotMongoWorker botMongoWorker = new BotMongoWorker(serverName, serverDriver.get(serverName)[1], chanelName); - if (botMongoWorker.isConsistent()) - return botMongoWorker; - else - System.out.println("BotDriver: Unable to use MongoWorker for "+serverName+". Using ZeroWorker instead."); // else, fall down and use BotZeroWorker. - case "Zero": + return validateConstancy(botMongoWorker, serverName, chanelName); + case "zero": return new BotZeroWorker(); default: System.out.println("Configuration issue: BotDriver->getWorker() can't find required driver \"" @@ -44,4 +43,13 @@ public class BotDriver { } return null; } + private static Worker validateConstancy(Worker worker, String srv, String chan){ // synchronized? + if (worker.isConsistent()){ + return worker; + } + else { + System.out.println("BotDriver: Unable to use "+worker.getClass().getSimpleName()+" for "+srv+"/"+chan+". Using ZeroWorker instead."); + return new BotZeroWorker(); + } + } } diff --git a/src/main/java/InnaIrcBot/LogDriver/BotFilesWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotFilesWorker.java index 28454be..82dd6e7 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotFilesWorker.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotFilesWorker.java @@ -16,31 +16,35 @@ public class BotFilesWorker implements Worker { private LocalDate fileWriterDay; private FileWriter fileWriter; - public BotFilesWorker(String server, String[] driverParameters, String channel){ - if (System.getProperty("os.name").startsWith("Windows")){ - channel = channel.replaceAll("\",",","); - } - else { - channel = channel.replaceAll("/",","); - } + private String ircServer; // hold for debug only - driverParameters[0] = driverParameters[0].trim(); //Consider parameters[0] as dirLocation - String dirLocation; - if (driverParameters[0].endsWith(File.separator)) - dirLocation = driverParameters[0]+server; + public BotFilesWorker(String server, String[] driverParameters, String channel){ + ircServer = server; + dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss"); + + channel = channel.replaceAll(File.separator, ","); + + String dirLocation = driverParameters[0].trim(); + if (dirLocation.endsWith(File.separator)) + dirLocation = dirLocation+server; else - dirLocation = driverParameters[0]+File.separator+server; - File dir = new File(dirLocation); - dir.mkdirs(); - if (!dir.exists()) { - System.out.println("Unable to create directory to store files: " + dirLocation); //TODO: notify requester - this.consistent = false; - } + dirLocation = dirLocation+File.separator+server; + this.filePath = dirLocation+File.separator+channel; - dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss"); - if (resetFileWriter(false)) - this.consistent = true; + File dir = new File(dirLocation); + 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("BotFilesWorker (@"+server+")->constructor(): Failure:\n\tUnable to create directory to store DB file: \n\t" +e); + return; // consistent = false; + } + if (!dir.exists()) { + System.out.println("BotFilesWorker (@"+server+")->constructor() failed:\n\tUnable to create directory to store files: " + dirLocation); //TODO: notify requester + return; + } + + this.consistent = resetFileWriter(false); } private boolean resetFileWriter(boolean reassign){ @@ -52,7 +56,7 @@ public class BotFilesWorker implements Worker { return true; } catch (java.io.IOException e){ - System.out.println("Internal issue: BotFilesWorker->constructor() can't create file to store logs: "+this.filePath); + System.out.println("BotFilesWorker (@"+ircServer+")->resetFileWriter() failed:\n\tCan't create file to store logs: "+this.filePath); return false; } } @@ -66,7 +70,7 @@ public class BotFilesWorker implements Worker { * argument[1] should be always 'subject' * */ @Override - public void logAdd(String event, String initiatorArg, String messageArg) { + public boolean logAdd(String event, String initiatorArg, String messageArg) { switch (event){ case "PRIVMSG": PRIVMSG(initiatorArg, messageArg); @@ -96,27 +100,31 @@ public class BotFilesWorker implements Worker { this.prettyPrint("["+LocalTime.now().format(dateFormat)+"] "+event+" "+initiatorArg+" "+messageArg+"\n"); // TODO: QA @ big data break; } - } - @Override - public void close() { - try { - fileWriter.close(); - } - catch (java.io.IOException e){ - System.out.println("Internal issue: BotFilesWorker->close() failed\n\tUnable to properly close file: "+this.filePath); // Live with it. - } - + return consistent; } private void prettyPrint(String string){ - if (LocalDate.now().isAfter(fileWriterDay)) - resetFileWriter(true); - try { - fileWriter.write(string); - fileWriter.flush(); - } catch (IOException e) { - System.out.println("Internal issue: BotFilesWorker->prettyPrint() failed\n\tUnable to write logs of "+this.filePath+" because of internal failure in LocalTime representation."); - consistent = false; - } + //if (consistent) { // could be not-opened + try { + if (LocalDate.now().isAfter(fileWriterDay)) { + if (!resetFileWriter(true)) { + this.close(); // Error message already printed + return; + } + } + fileWriter.write(string); + fileWriter.flush(); + } catch (IOException e) { + System.out.println("BotFilesWorker (@" + ircServer + ")->prettyPrint() failed\n\tUnable to write logs of " + this.filePath + " because of internal failure in LocalTime representation."); + this.close(); + //consistent = false; + } catch (NullPointerException npe){ + System.out.println("BotFilesWorker (@" + ircServer + ")->prettyPrint() failed\n\tUnable to write logs of " + this.filePath + " because file descriptor already closed/was not opened."); + consistent = false; + } catch (Exception unknowne){ // ??? No ideas. Just in case. Consider removing. + System.out.println("BotFilesWorker (@" + ircServer + ")->prettyPrint() failed\n\tUnable to write logs of " + this.filePath + " because of exception:\n\t"+unknowne); + this.close(); + } + //} } private String genDate(){ return "["+LocalTime.now().format(dateFormat)+"] "; @@ -160,4 +168,16 @@ public class BotFilesWorker implements Worker { private void TOPIC(String initiatorArg, String messageArg) { this.prettyPrint(genDate()+"-!- "+getUserNameAndHost(initiatorArg)+"has changed topic to: "+messageArg.replaceAll("^.+?:", "")+"\n"); } + + @Override + public void close() { + try { + if (fileWriter !=null) + fileWriter.close(); + } + catch (java.io.IOException e){ + System.out.println("BotFilesWorker (@"+ircServer+")->close() failed\n\tUnable to properly close file: "+this.filePath); // Live with it. + } + this.consistent = false; + } } diff --git a/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java index ea20cbb..840e041 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java @@ -11,17 +11,19 @@ import org.bson.Document; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; + /** For each IRC server we create one DB that stored in the hashmap ('static', since we may have few configuration that have to work at once) * For each channel we store collection that have name of the ircServer + chanelName. * If user decides to use one MongoDB for various servers, he may use even one DB (declared in configuration file) and store collections in there. * **/ -public class BotMongoWorker implements Worker { +public class BotMongoWorker implements Worker { //TODO consider skipping checks if server already added. private static Map serversMap = Collections.synchronizedMap(new HashMap()); private String ircServer; private MongoCollection collection; - private boolean consistent = false; // TODO: clarify possible issues??? + private boolean consistent = false; private boolean isItSystemThread = false; @@ -85,7 +87,6 @@ public class BotMongoWorker implements Worker { @Override public void serverDescriptionChanged(ServerDescriptionChangedEvent serverDescriptionChangedEvent) { if (!serverDescriptionChangedEvent.getNewDescription().isOk()) { - consistent = false; close(ircServer); // ircServer recieved by constructor, not this.ircServer System.out.println("BotMongoWorker (@"+ircServer+"): ServerListener: Server description changed (exception occurs): " + serverDescriptionChangedEvent.getNewDescription().getException()); @@ -96,6 +97,7 @@ public class BotMongoWorker implements Worker { MongoClientSettings MCS = MongoClientSettings.builder() // .addCommandListener(mongoCommandListener) .applyConnectionString(new ConnectionString("mongodb://"+mongoHostAddr)) + .applyToClusterSettings(builder -> builder.serverSelectionTimeout(5, TimeUnit.SECONDS)) .applyToServerSettings(builder -> builder.addServerListener(mongoServerListener)) .credential(MongoCredential.createCredential(mongoUser, mongoDBName, mongoPass.toCharArray())) .build(); @@ -107,30 +109,33 @@ public class BotMongoWorker implements Worker { MongoDatabase mongoDB = serversMap.get(ircServer).getDatabase(mongoDBName); collection = mongoDB.getCollection(ircServer + channel); - Document ping = new Document("ping", "1"); + Document ping = new Document("ping", 1); + // try { - collection.insertOne(ping); - consistent = true; // if no exceptions, then true + 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(ircServer); + return; + } + consistent = true; } catch (MongoCommandException mce){ System.out.println("BotMongoWorker (@"+this.ircServer+"): Command exception. Check if username/password set correctly."); - consistent = false; close(ircServer); // ircServer received by constructor, not this.ircServer } catch (MongoTimeoutException mte) { - System.out.println("BotMongoWorker (@"+this.ircServer+"): Timeout exception"); - consistent = false; + System.out.println("BotMongoWorker (@"+this.ircServer+"): Timeout exception."); close(ircServer); // ircServer received by constructor, not this.ircServer }catch (MongoException me){ - System.out.println("BotMongoWorker (@"+this.ircServer+"): MongoDB Exception"); - consistent = false; + System.out.println("BotMongoWorker (@"+this.ircServer+"): MongoDB Exception."); close(ircServer); // ircServer received by constructor, not this.ircServer } catch (IllegalStateException ise){ System.out.println("BotMongoWorker (@"+this.ircServer+"): Illegal state exception: MongoDB server already closed (not an issue)."); consistent = false; + // no need to close() obviously } } @Override - public void logAdd(String event, String initiatorArg, String messageArg) { + public boolean logAdd(String event, String initiatorArg, String messageArg) { Document document = new Document("date", getDate()) .append("event", event) .append("initiator", initiatorArg); @@ -163,7 +168,23 @@ public class BotMongoWorker implements Worker { //preparedStatement.setString(5,null); break; } - collection.insertOne(document); // TODO: try/catch and watch + try { + collection.insertOne(document); // TODO: call finalize? + consistent = true; // if no exceptions, then true + } catch (MongoCommandException mce){ + System.out.println("BotMongoWorker (@"+this.ircServer+")->logAdd(): Command exception. Check if username/password set correctly."); + this.close(); + } catch (MongoTimeoutException mte) { + System.out.println("BotMongoWorker (@"+this.ircServer+")->logAdd(): Timeout exception."); + this.close(); + }catch (MongoException me){ + System.out.println("BotMongoWorker (@"+this.ircServer+")->logAdd(): MongoDB Exception."); + this.close(); + } catch (IllegalStateException ise){ + System.out.println("BotMongoWorker (@"+this.ircServer+")->logAdd(): Illegal state exception: MongoDB server already closed (not an issue)."); + this.close(); + } + return consistent; } private long getDate(){ return System.currentTimeMillis() / 1000L; } // UNIX time @@ -178,14 +199,16 @@ public class BotMongoWorker implements Worker { if (this.isItSystemThread && serversMap.containsKey(ircServer)) { serversMap.get(ircServer).close(); serversMap.remove(ircServer); - System.out.println("BotMongoWorker (@"+this.ircServer+")->close(): " + ircServer); + //System.out.println("BotMongoWorker (@"+this.ircServer+")->close()"); // expected exit } + consistent = false; } - public void close(String server) { + private void close(String server) { if (serversMap.containsKey(server)) { serversMap.get(server).close(); serversMap.remove(server); - System.out.println("BotMongoWorker (@"+this.ircServer+")->close(): " + server + " (forced by listeners)"); + System.out.println("BotMongoWorker (@"+this.ircServer+")->close() [forced by listeners]"); } + consistent = false; } -} +} \ No newline at end of file diff --git a/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java index 183e08f..f862468 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotSQLiteWorker.java @@ -11,16 +11,24 @@ public class BotSQLiteWorker implements Worker { private Connection connection; private boolean consistent = false; private PreparedStatement preparedStatement; + + private String ircServer; /** * Don't even think of changing this balalaika. * */ - public BotSQLiteWorker(String server, String[] driverParameters, String channel){ // TODO: threads on SQLite level // remember: One file one DB + public BotSQLiteWorker(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]); - dir.mkdirs(); // TODO: Check if not-null - if (!dir.exists()) { - System.out.println("Unable to create directory to store DB file: " + driverParameters[0]); //TODO: notify requester - this.consistent = false; + 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; } String connectionURL; if (driverParameters[0].endsWith(File.separator)) @@ -28,7 +36,7 @@ public class BotSQLiteWorker implements Worker { else connectionURL = "jdbc:sqlite:"+driverParameters[0]+File.separator+server+".db"; - String safeChanName = channel.trim().replaceAll("\"","\\\""); // TODO: use trim in every driver/worker? + 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 @@ -37,7 +45,7 @@ public class BotSQLiteWorker implements Worker { if (connection != null){ // Create table if not created Statement statement = connection.createStatement(); - String query = "CREATE TABLE IF NOT EXISTS \""+safeChanName+"\" (" + String query = "CREATE TABLE IF NOT EXISTS \""+channel+"\" (" + " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + " unixtime INTEGER," + " event TEXT," @@ -48,7 +56,7 @@ public class BotSQLiteWorker implements Worker { statement.executeUpdate(query); // Check table representation - ResultSet rs = statement.executeQuery("PRAGMA table_info(\""+safeChanName+"\");"); // executeQuery never null + ResultSet rs = statement.executeQuery("PRAGMA table_info(\""+channel+"\");"); // executeQuery never null boolean[] schemaResultCheck = {false, false, false, false, false, false}; while (rs.next()) { @@ -116,8 +124,8 @@ public class BotSQLiteWorker implements Worker { // 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: Found already existing table for channel with incorrect syntax: removing table and re-creating."); - statement.executeUpdate("DROP TABLE \"" + safeChanName + "\";"); + 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; } @@ -125,17 +133,18 @@ public class BotSQLiteWorker implements Worker { this.consistent = true; this.preparedStatement = connection.prepareStatement( - "INSERT INTO \""+safeChanName + "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; } } catch (SQLException e){ - System.out.println("Internal issue: BotSQLiteWorker->constructor() failed\n\t"+e); - this.consistent = false; + System.out.println("BotSQLiteWorker (@"+server+")->constructor() failed:\n\t"+e); + this.consistent = false; // this.close(); } } @@ -146,7 +155,7 @@ public class BotSQLiteWorker implements Worker { public boolean isConsistent() {return consistent; } @Override - public void logAdd(String event, String initiatorArg, String messageArg) { + public boolean logAdd(String event, String initiatorArg, String messageArg) { try { preparedStatement.setLong(1, getDate()); preparedStatement.setString(2, event); @@ -182,10 +191,14 @@ public class BotSQLiteWorker implements Worker { } preparedStatement.executeUpdate(); } - catch (SQLException e){ - System.out.println("Internal issue: BotSQLiteWorker->logAdd() failed\n\t"+e); - this.consistent = false; + 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 } + return consistent; } @Override @@ -194,8 +207,9 @@ public class BotSQLiteWorker implements Worker { //System.out.println("SQLite drier closed"); this.connection.close(); } - catch (SQLException e){ - System.out.println("Internal issue: BotSQLiteWorker->close() failed\n\t" + e); + catch (SQLException | NullPointerException e){ //todo: consider redo + System.out.println("BotSQLiteWorker (@"+ircServer+")->close() failed:\n\t" + e); // nothing to do here } + this.consistent = false; } } \ No newline at end of file diff --git a/src/main/java/InnaIrcBot/LogDriver/BotZeroWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotZeroWorker.java index 17237f4..e3aead6 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotZeroWorker.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotZeroWorker.java @@ -5,7 +5,7 @@ public class BotZeroWorker implements Worker{ public boolean isConsistent() {return true;} @Override - public void logAdd(String event, String initiatorArg, String messageArg) {} + public boolean logAdd(String event, String initiatorArg, String messageArg) { return true; } @Override public void close() {} diff --git a/src/main/java/InnaIrcBot/LogDriver/Worker.java b/src/main/java/InnaIrcBot/LogDriver/Worker.java index 8f111a3..8449d77 100644 --- a/src/main/java/InnaIrcBot/LogDriver/Worker.java +++ b/src/main/java/InnaIrcBot/LogDriver/Worker.java @@ -5,7 +5,7 @@ public interface Worker { boolean isConsistent(); - void logAdd(String event, + boolean logAdd(String event, String initiatorArg, String messageArg); diff --git a/src/main/java/Temporary/DriverTest.java b/src/main/java/Temporary/DriverTest.java deleted file mode 100644 index 6b3e0be..0000000 --- a/src/main/java/Temporary/DriverTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package Temporary; - -import InnaIrcBot.LogDriver.BotDriver; -import InnaIrcBot.LogDriver.Worker; - -public class DriverTest { - - public static void main(String[] args){ - if (BotDriver.setLogDriver("irc.tomsk.net", "MongoDB", new String[]{"192.168.1.5:27017", - "irc", - "loper", - "password"})) - System.out.println("Successful driver initiation"); - else { - System.out.println("Failed driver initiation"); - return; - } - - Worker fw1 = BotDriver.getWorker("irc.tomsk.net","system"); - Worker fw2 = BotDriver.getWorker("irc.tomsk.net","#main"); - Worker fw3 = BotDriver.getWorker("irc.tomsk.net","#lpr"); - - if ((fw1 !=null) && (fw2 !=null) && (fw3 !=null)){ - System.out.println("LogFile1: "+fw1.isConsistent()); - System.out.println("LogFile2: "+fw2.isConsistent()); - System.out.println("LogFile3: "+fw3.isConsistent()); - - fw1.logAdd("JOIN", "de_su!loper@desktop.lan", "message1"); - fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); - fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); - fw1.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); - fw1.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); - fw1.logAdd("PART", "de_su!loper@desktop.lan", "#chan1"); - - fw2.logAdd("JOIN", "de_su!loper@desktop.lan", "message2"); - fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); - fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); - fw2.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); - fw2.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); - fw2.logAdd("PART", "de_su!loper@desktop.lan", "#chan2"); - - fw3.logAdd("JOIN", "de_su!loper@desktop.lan", "message3"); - fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); - fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); - fw3.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); - fw3.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); - fw3.logAdd("PART", "de_su!loper@desktop.lan", "#chan3"); - - fw1.close(); - fw2.close(); - fw3.close(); - } - } -} diff --git a/src/main/java/Temporary/DriverTestFiles.java b/src/main/java/Temporary/DriverTestFiles.java new file mode 100644 index 0000000..b3df7ea --- /dev/null +++ b/src/main/java/Temporary/DriverTestFiles.java @@ -0,0 +1,71 @@ +package Temporary; + +import InnaIrcBot.LogDriver.BotDriver; +import InnaIrcBot.LogDriver.Worker; + +public class DriverTestFiles { + + public static void main(String[] args){ + if (BotDriver.setLogDriver("irc.tomsk.net", "files", new String[]{"/tmp/logs/"})) + System.out.println("DRVT_Files: Successful driver initiation"); + else { + System.out.println("DRVT_Files: Failed driver initiation"); + return; + } + + Worker fw1 = BotDriver.getWorker("irc.tomsk.net","system"); + Worker fw2 = BotDriver.getWorker("irc.tomsk.net","#main"); + Worker fw3 = BotDriver.getWorker("irc.tomsk.net","#lpr"); + + if ((fw1 !=null) && (fw2 !=null) && (fw3 !=null)){ + System.out.println("DRVT_Files:LogFile1: "+fw1.isConsistent()); + System.out.println("DRVT_Files:LogFile2: "+fw2.isConsistent()); + System.out.println("DRVT_Files:LogFile3: "+fw3.isConsistent()); + boolean res; + + res = fw1.logAdd("JOIN", "de_su!loper@desktop.lan", "message1"); + System.out.println("DRVT_Files:fw1 exec result: "+res); + res = fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + System.out.println("DRVT_Files:fw1 exec result: "+res); + res = fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + System.out.println("DRVT_Files:fw1 exec result: "+res); + res = fw1.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + System.out.println("DRVT_Files:fw1 exec result: "+res); + res = fw1.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); + System.out.println("DRVT_Files:fw1 exec result: "+res); + res = fw1.logAdd("PART", "de_su!loper@desktop.lan", "#chan1"); + System.out.println("DRVT_Files:fw1 exec result: "+res); + + res = fw2.logAdd("JOIN", "de_su!loper@desktop.lan", "message2"); + System.out.println("DRVT_Files:fw2 exec result: "+res); + res = fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + System.out.println("DRVT_Files:fw2 exec result: "+res); + res = fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + System.out.println("DRVT_Files:fw2 exec result: "+res); + + res = fw2.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + System.out.println("DRVT_Files:fw2 exec result: "+res); + res = fw2.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); + System.out.println("DRVT_Files:fw2 exec result: "+res); + res = fw2.logAdd("PART", "de_su!loper@desktop.lan", "#chan2"); + System.out.println("DRVT_Files:fw2 exec result: "+res); + + res = fw3.logAdd("JOIN", "de_su!loper@desktop.lan", "message3"); + System.out.println("DRVT_Files:fw3 exec result: "+res); + res = fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + System.out.println("DRVT_Files:fw3 exec result: "+res); + res = fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + System.out.println("DRVT_Files:fw3 exec result: "+res); + res = fw3.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + System.out.println("DRVT_Files:fw3 exec result: "+res); + res = fw3.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); + System.out.println("DRVT_Files:fw3 exec result: "+res); + res = fw3.logAdd("PART", "de_su!loper@desktop.lan", "#chan3"); + System.out.println("DRVT_Files:fw3 exec result: "+res); + + fw1.close(); + fw2.close(); + fw3.close(); + } + } +} diff --git a/src/main/java/Temporary/DriverTestMongo.java b/src/main/java/Temporary/DriverTestMongo.java new file mode 100644 index 0000000..ad89701 --- /dev/null +++ b/src/main/java/Temporary/DriverTestMongo.java @@ -0,0 +1,73 @@ +package Temporary; + +import InnaIrcBot.LogDriver.BotDriver; +import InnaIrcBot.LogDriver.Worker; + +public class DriverTestMongo { + + public static void main(String[] args){ + if (BotDriver.setLogDriver("irc.tomsk.net", "MongoDB", new String[]{"192.168.1.186:27017", + "irc", + "loper", + "password"})) + System.out.println("DRVT_Mongo:Successful driver initiation"); + else { + System.out.println("DRVT_Mongo:Failed driver initiation"); + return; + } + + Worker fw1 = BotDriver.getWorker("irc.tomsk.net","system"); + Worker fw2 = BotDriver.getWorker("irc.tomsk.net","#main"); + Worker fw3 = BotDriver.getWorker("irc.tomsk.net","#lpr"); + + if ((fw1 !=null) && (fw2 !=null) && (fw3 !=null)){ + System.out.println("DRVT_Mongo:LogFile1: "+fw1.isConsistent()); + System.out.println("DRVT_Mongo:LogFile2: "+fw2.isConsistent()); + System.out.println("DRVT_Mongo:LogFile3: "+fw3.isConsistent()); + boolean res; + + res = fw1.logAdd("JOIN", "de_su!loper@desktop.lan", "message1"); + System.out.println("DRVT_Mongo:fw1 exec result: "+res); + res = fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + System.out.println("DRVT_Mongo:fw1 exec result: "+res); + res = fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + System.out.println("DRVT_Mongo:fw1 exec result: "+res); + res = fw1.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + System.out.println("DRVT_Mongo:fw1 exec result: "+res); + res = fw1.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); + System.out.println("DRVT_Mongo:fw1 exec result: "+res); + res = fw1.logAdd("PART", "de_su!loper@desktop.lan", "#chan1"); + System.out.println("DRVT_Mongo:fw1 exec result: "+res); + + res = fw2.logAdd("JOIN", "de_su!loper@desktop.lan", "message2"); + System.out.println("DRVT_Mongo:fw2 exec result: "+res); + res = fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + System.out.println("DRVT_Mongo:fw2 exec result: "+res); + res = fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + System.out.println("DRVT_Mongo:fw2 exec result: "+res); + res = fw2.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + System.out.println("DRVT_Mongo:fw2 exec result: "+res); + res = fw2.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); + System.out.println("DRVT_Mongo:fw2 exec result: "+res); + res = fw2.logAdd("PART", "de_su!loper@desktop.lan", "#chan2"); + System.out.println("DRVT_Mongo:fw2 exec result: "+res); + + res = fw3.logAdd("JOIN", "de_su!loper@desktop.lan", "message3"); + System.out.println("DRVT_Mongo:fw3 exec result: "+res); + res = fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + System.out.println("DRVT_Mongo:fw3 exec result: "+res); + res = fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + System.out.println("DRVT_Mongo:fw3 exec result: "+res); + res = fw3.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + System.out.println("DRVT_Mongo:fw3 exec result: "+res); + res = fw3.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); + System.out.println("DRVT_Mongo:fw3 exec result: "+res); + res = fw3.logAdd("PART", "de_su!loper@desktop.lan", "#chan3"); + System.out.println("DRVT_Mongo:fw3 exec result: "+res); + + fw1.close(); + fw2.close(); + fw3.close(); + } + } +} diff --git a/src/main/java/Temporary/DriverTestSQLite.java b/src/main/java/Temporary/DriverTestSQLite.java new file mode 100644 index 0000000..7b0c674 --- /dev/null +++ b/src/main/java/Temporary/DriverTestSQLite.java @@ -0,0 +1,70 @@ +package Temporary; + +import InnaIrcBot.LogDriver.BotDriver; +import InnaIrcBot.LogDriver.Worker; + +public class DriverTestSQLite { + + public static void main(String[] args){ + if (BotDriver.setLogDriver("irc.tomsk.net", "SQLite", new String[]{"/tmp/logs/mylogs"})) + System.out.println("DRVT_SQLite:Successful driver initiation"); + else { + System.out.println("DRVT_SQLite:Failed driver initiation"); + return; + } + + Worker fw1 = BotDriver.getWorker("irc.tomsk.net","system"); + Worker fw2 = BotDriver.getWorker("irc.tomsk.net","#main"); + Worker fw3 = BotDriver.getWorker("irc.tomsk.net","#lpr"); + + if ((fw1 !=null) && (fw2 !=null) && (fw3 !=null)){ + System.out.println("DRVT_SQLite:LogFile1: "+fw1.isConsistent()); + System.out.println("DRVT_SQLite:LogFile2: "+fw2.isConsistent()); + System.out.println("DRVT_SQLite:LogFile3: "+fw3.isConsistent()); + boolean res; + + res = fw1.logAdd("JOIN", "de_su!loper@desktop.lan", "message1"); + System.out.println("DRVT_SQLite:fw1 exec result: "+res); + res = fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + System.out.println("DRVT_SQLite:fw1 exec result: "+res); + res = fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + System.out.println("DRVT_SQLite:fw1 exec result: "+res); + res = fw1.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + System.out.println("DRVT_SQLite:fw1 exec result: "+res); + res = fw1.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); + System.out.println("DRVT_SQLite:fw1 exec result: "+res); + res = fw1.logAdd("PART", "de_su!loper@desktop.lan", "#chan1"); + System.out.println("DRVT_SQLite:fw1 exec result: "+res); + + res = fw2.logAdd("JOIN", "de_su!loper@desktop.lan", "message2"); + System.out.println("DRVT_SQLite:fw2 exec result: "+res); + res = fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + System.out.println("DRVT_SQLite:fw2 exec result: "+res); + res = fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + System.out.println("DRVT_SQLite:fw2 exec result: "+res); + res = fw2.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + System.out.println("DRVT_SQLite:fw2 exec result: "+res); + res = fw2.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); + System.out.println("DRVT_SQLite:fw2 exec result: "+res); + res = fw2.logAdd("PART", "de_su!loper@desktop.lan", "#chan2"); + System.out.println("DRVT_SQLite:fw2 exec result: "+res); + + res = fw3.logAdd("JOIN", "de_su!loper@desktop.lan", "message3"); + System.out.println("DRVT_SQLite:fw3 exec result: "+res); + res = fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"); + System.out.println("DRVT_SQLite:fw3 exec result: "+res); + res = fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"); + System.out.println("DRVT_SQLite:fw3 exec result: "+res); + res = fw3.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"); + System.out.println("DRVT_SQLite:fw3 exec result: "+res); + res = fw3.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"); + System.out.println("DRVT_SQLite:fw3 exec result: "+res); + res = fw3.logAdd("PART", "de_su!loper@desktop.lan", "#chan3"); + System.out.println("DRVT_SQLite:fw3 exec result: "+res); + + fw1.close(); + fw2.close(); + fw3.close(); + } + } +} From cd1e70838ce3a494006a359d1f3ae09adf3d1777 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Sat, 26 Jan 2019 00:33:52 +0300 Subject: [PATCH 5/6] v0.4 stabilization --- .../Commanders/PrivateMsgCommander.java | 1 - .../java/InnaIrcBot/LogDriver/BotDriver.java | 13 +++-- .../ProvidersConsumers/ChanConsumer.java | 49 ++++++++++++------- .../ProvidersConsumers/SystemConsumer.java | 2 + 4 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/main/java/InnaIrcBot/Commanders/PrivateMsgCommander.java b/src/main/java/InnaIrcBot/Commanders/PrivateMsgCommander.java index 137f643..02d7641 100644 --- a/src/main/java/InnaIrcBot/Commanders/PrivateMsgCommander.java +++ b/src/main/java/InnaIrcBot/Commanders/PrivateMsgCommander.java @@ -25,7 +25,6 @@ public class PrivateMsgCommander { // T if (cmd.length > 1) cmd[1] = cmd[1].trim(); - switch (cmd[0]){ case "tell": if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) { diff --git a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java index 4099f46..e416f2c 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java @@ -35,20 +35,27 @@ public class BotDriver { case "zero": return new BotZeroWorker(); default: - System.out.println("Configuration issue: BotDriver->getWorker() can't find required driver \"" + System.out.println("BotDriver->getWorker(): Configuration issue: can't find required driver \"" +serverDriver.get(serverName)[0][0] +"\".Using \"ZeroWorker\"."); return new BotZeroWorker(); } } - return null; + System.out.println("BotDriver->getWorker(): Unknown issue: Channel exists for non-existing server.\n\tUsing ZeroWorker."); + return new BotZeroWorker(); + } + // 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 BotZeroWorker(); } private static Worker validateConstancy(Worker worker, String srv, String chan){ // synchronized? if (worker.isConsistent()){ return worker; } else { - System.out.println("BotDriver: Unable to use "+worker.getClass().getSimpleName()+" for "+srv+"/"+chan+". Using ZeroWorker instead."); + System.out.println("BotDriver->validateConstancy(): Unable to use " + +worker.getClass().getSimpleName()+" for "+srv+"/"+chan + +". Using ZeroWorker instead."); return new BotZeroWorker(); } } diff --git a/src/main/java/InnaIrcBot/ProvidersConsumers/ChanConsumer.java b/src/main/java/InnaIrcBot/ProvidersConsumers/ChanConsumer.java index 8762110..70e4079 100644 --- a/src/main/java/InnaIrcBot/ProvidersConsumers/ChanConsumer.java +++ b/src/main/java/InnaIrcBot/ProvidersConsumers/ChanConsumer.java @@ -54,13 +54,16 @@ public class ChanConsumer implements Runnable { if (!trackUsers(dataStrings[0], dataStrings[1], dataStrings[2])) continue; - writerWorker.logAdd(dataStrings[0], dataStrings[1], dataStrings[2]); // Send to chanel commander thread chanelCommanderPipe.println(data); chanelCommanderPipe.flush(); //System.out.println("|"+dataStrings[0]+"|"+dataStrings[1]+"|"+dataStrings[2]+"|"); //System.out.println("Thread: "+this.channelName +"\n\tArray:"+ userList); + if (!writerWorker.logAdd(dataStrings[0], dataStrings[1], dataStrings[2])){ // Write logs, check if LogDriver consistent. If not: + this.fixLogDriverIssues(dataStrings[0], dataStrings[1], dataStrings[2]); + } + if (endThread) { reader.close(); chanList.get(channelName).close(); @@ -69,7 +72,7 @@ public class ChanConsumer implements Runnable { } } } catch (java.io.IOException e){ - System.out.println("Internal issue: thread ChanConsumer->run() caused I/O exception:\n\t"+e); // TODO: reconnect + System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->run(): Internal issue in thread: caused I/O exception:\n\t"+e); // TODO: reconnect } writerWorker.close(); //Chanel commander thread's pipe should be closed @@ -82,25 +85,25 @@ public class ChanConsumer implements Runnable { case "PRIVMSG": // most common, we don't have to handle anything else return true; case "JOIN": - addUsers(initiatorArg); + addUsers(simplifyNick(initiatorArg)); return true; case "PART": - delUsers(initiatorArg); + delUsers(simplifyNick(initiatorArg)); // nick non-simple return true; - case "QUIT": // TODO fix: use regex - if (userList.contains(initiatorArg.replaceAll("!.+$", ""))) { - delUsers(initiatorArg); + case "QUIT": + if (userList.contains(simplifyNick(initiatorArg))) { + delUsers(simplifyNick(initiatorArg)); // nick non-simple return true; } else return false; // user quit, but he/she is not in this channel case "KICK": - if (rejoin && nick.equals(subjectArg.substring(subjectArg.indexOf(" ") + 1, subjectArg.indexOf(" :")))) + if (rejoin && nick.equals(subjectArg.replaceAll("(^.+?\\s)|(\\s.+$)", ""))) // if it's me and I have rejoin policy 'Auto-Rejoin on kick'. StreamProvider.writeToStream(serverName, "JOIN " + channelName); - delUsers(subjectArg.substring(subjectArg.indexOf(" ") + 1, subjectArg.indexOf(" :"))); + delUsers(subjectArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")); // nick already simplified return true; case "NICK": - if (userList.contains(initiatorArg.replaceAll("!.+$", ""))) { - swapUsers(initiatorArg, subjectArg); + if (userList.contains(simplifyNick(initiatorArg))) { + swapUsers(simplifyNick(initiatorArg), subjectArg); return true; } else { return false; // user changed nick, but he/she is not in this channel @@ -111,19 +114,19 @@ public class ChanConsumer implements Runnable { } private void addUsers(String user){ - if (!userList.contains(user.replaceAll("!.+$", ""))) - userList.add(user.replaceAll("!.+$", "")); + if (!userList.contains(user)) + userList.add(user); } private void delUsers(String user){ - if (user.replaceAll("!.+$", "").equals(nick)) { + if (user.equals(nick)) { endThread = true; } - userList.remove(user.replaceAll("!.+$", "")); + userList.remove(user); } private void swapUsers(String userNickOld, String userNickNew){ - userList.remove(userNickOld.replaceAll("!.+$", "")); + userList.remove(userNickOld); userList.add(userNickNew); - if (userNickOld.replaceAll("!.+$", "").equals(nick)) + if (userNickOld.equals(nick)) this.nick = userNickNew; } // Create ChanelCommander @@ -142,9 +145,19 @@ public class ChanConsumer implements Runnable { return new PrintWriter(streamOut); } catch (IOException e) { - System.out.println("Internal issue: ChanConsumer->getChanelCommander() I/O exception while initialized child objects."); // caused by Socket + System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->getChanelCommander(): Internal issue: I/O exception while initialized child objects:\n\t"+e); // caused by Socket endThread = true; return null; } } + private String simplifyNick(String nick){ return nick.replaceAll("!.*$",""); } + + private void fixLogDriverIssues(String a, String b, String c){ + System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->fixLogDriverIssues(): Some issues detected. Trying to fix..."); + this.writerWorker = BotDriver.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 = BotDriver.getZeroWorker(); + System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->fixLogDriverIssues(): failed to use defined LogDriver. Using ZeroWorker instead."); + } + } } diff --git a/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java b/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java index 4689807..ecaca32 100644 --- a/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java +++ b/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java @@ -29,7 +29,9 @@ public class SystemConsumer implements Runnable{ private PrivateMsgCommander commander; SystemConsumer(BufferedReader streamReader, String userNick, Map map, StorageFile storage) { + this.writerWorker = BotDriver.getWorker(storage.getServerName(), "system"); + this.nick = userNick; this.serverName = storage.getServerName(); this.channelsMap = map; From 9fe3b5e11b7dbcb4de88312979b840a7295f9598 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Sun, 27 Jan 2019 06:19:31 +0300 Subject: [PATCH 6/6] v0.4 release --- .../mongoDriverExample.config | 25 +++++ README.md | 5 +- .../java/InnaIrcBot/Config/StorageFile.java | 6 +- .../java/InnaIrcBot/Config/StorageReader.java | 3 +- .../java/InnaIrcBot/LogDriver/BotDriver.java | 12 +- .../InnaIrcBot/LogDriver/BotFilesWorker.java | 2 +- .../InnaIrcBot/LogDriver/BotMongoWorker.java | 31 +++-- .../InnaIrcBot/LogDriver/BotSystemWorker.java | 106 ++++++++++++++++++ .../InnaIrcBot/LogDriver/SystemWorker.java | 12 ++ .../LogDriver/ThingToCloseOnDie.java | 5 + .../ProvidersConsumers/DataProvider.java | 2 +- .../ProvidersConsumers/SystemConsumer.java | 57 +++++----- src/main/java/Temporary/DriverTestFiles.java | 2 +- src/main/java/Temporary/DriverTestMongo.java | 3 +- src/main/java/Temporary/DriverTestSQLite.java | 2 +- src/main/java/Temporary/StorageFileTest.java | 1 + 16 files changed, 223 insertions(+), 51 deletions(-) create mode 100644 ConfigurationExamples/mongoDriverExample.config create mode 100644 src/main/java/InnaIrcBot/LogDriver/BotSystemWorker.java create mode 100644 src/main/java/InnaIrcBot/LogDriver/SystemWorker.java create mode 100644 src/main/java/InnaIrcBot/LogDriver/ThingToCloseOnDie.java diff --git a/ConfigurationExamples/mongoDriverExample.config b/ConfigurationExamples/mongoDriverExample.config new file mode 100644 index 0000000..a859d9d --- /dev/null +++ b/ConfigurationExamples/mongoDriverExample.config @@ -0,0 +1,25 @@ +{ + "serverName": "irc.tomsk.net", + "serverPort": 6666, + "serverPass": "", + "channels": [ + "#lpr" + ], + "userNick": "InnaBot", + "userIdent": "rusnet", + "userRealName": "IRCBot", + "userNickPass": "", + "userNickAuthStyle": "rusnet", + "userMode": "x", + "rejoinOnKick": true, + "logDriver": "MongoDB", + "logDriverParameters": [ + "192.168.1.186:27017", + "irc", + "mongo_user_name", + "mongo_password" + ], + "botAdministratorPassword": "very_secret_password", + "chanelConfigurationsPath": "/home/USERNAME/TSV_CONF_FOLDER/", + "applicationLogDir": "/tmp/appLogs" +} \ No newline at end of file diff --git a/README.md b/README.md index 255f7a0..884557f 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Another one IRC bot in deep-deep beta. "logDriver" could be "Files", "SQLite" or "Zero" * Files - log everything to files using /yourPathSet/serverName/#chanelName_YYYY-MM-DD.txt format. * SQLite - use /yourPathSet/server.db (or /yourPathSet/yourFileName.db) sqlite file. +* MongoDB - write files to MongoDB. See ConfigurationExamples folder. ## License Source code spreads under the GNU General Public License v3 or higher. Please see LICENSE file. @@ -31,7 +32,7 @@ Used libraries: - [ ] Code refactoring - [ ] QA: good regression testing - [x] CI/CD Jenkins -- [ ] Suppress messages from server or handle them separately from selected worker +- [x] Suppress messages from server or handle them separately from selected worker - [ ] Logs backend workers as threads (SQLite and co. are too slow) - [x] Logs backend worker for mongodb - [ ] Logs backend worker for redis/redis node @@ -44,4 +45,4 @@ Used libraries: - [ ] ncurses-like or/and GUI configuration files (server/chanel setting) editor - [ ] CTCP support for using @ 'ChanelCommander' - [ ] Access roles support (i.e. delegating some rights to another users) -- [ ] Logs for application \ No newline at end of file +- [ ] Logs for application (partly implemented) \ No newline at end of file diff --git a/src/main/java/InnaIrcBot/Config/StorageFile.java b/src/main/java/InnaIrcBot/Config/StorageFile.java index 8f74842..9cc5634 100644 --- a/src/main/java/InnaIrcBot/Config/StorageFile.java +++ b/src/main/java/InnaIrcBot/Config/StorageFile.java @@ -16,6 +16,7 @@ public class StorageFile { private final String[] logDriverParameters; private final String botAdministratorPassword; private final String chanelConfigurationsPath; + private final String applicationLogDir; public String getServerName() { return serverName; } public int getServerPort() { return serverPort; } @@ -32,6 +33,7 @@ public class StorageFile { public String[] getLogDriverParameters() { return logDriverParameters; } public String getBotAdministratorPassword() { return botAdministratorPassword; } public String getChanelConfigurationsPath() { return chanelConfigurationsPath; } + public String getApplicationLogDir() { return applicationLogDir; } public StorageFile(String serverName, int serverPort, @@ -47,7 +49,8 @@ public class StorageFile { String logDriver, String[] logDriverParameters, String botAdministratorPassword, - String chanelConfigurationsPath){ + String chanelConfigurationsPath, + String applicationLogDir){ this.serverName = serverName; this.serverPort = serverPort; this.serverPass = serverPass; @@ -63,5 +66,6 @@ public class StorageFile { this.logDriverParameters = logDriverParameters; this.botAdministratorPassword = botAdministratorPassword; this.chanelConfigurationsPath = chanelConfigurationsPath; + this.applicationLogDir = applicationLogDir; } } diff --git a/src/main/java/InnaIrcBot/Config/StorageReader.java b/src/main/java/InnaIrcBot/Config/StorageReader.java index e2b8b48..a3ce54f 100644 --- a/src/main/java/InnaIrcBot/Config/StorageReader.java +++ b/src/main/java/InnaIrcBot/Config/StorageReader.java @@ -78,7 +78,8 @@ public class StorageReader { "Files", new String[] {System.getProperty("user.home")}, "pswd", - System.getProperty("user.home") + System.getProperty("user.home"), + "/var/logs/" ); Gson writingStorageObject = new GsonBuilder().setPrettyPrinting().create(); diff --git a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java index e416f2c..daf2a0b 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotDriver.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotDriver.java @@ -4,17 +4,20 @@ import java.util.HashMap; public class BotDriver { private static HashMap serverDriver = new HashMap<>(); + + private static HashMap systemLogWorkerMap = new HashMap<>(); /** * Define driver for desired server * */ // TODO: add proxy worker for using with multiple drivers - public static synchronized boolean setLogDriver(String serverName, String driver, String[] driverParams){ + public static synchronized boolean setLogDriver(String serverName, String driver, String[] driverParams, String applicationLogDir){ if (!driver.isEmpty() && driverParams != null && driverParams.length > 0 && driverParams[0] != null && !driverParams[0].isEmpty()) { String[][] drvAndParams = { {driver}, driverParams }; serverDriver.put(serverName, drvAndParams); + systemLogWorkerMap.put(serverName, new BotSystemWorker(serverName, applicationLogDir)); return true; } else @@ -45,9 +48,12 @@ public class BotDriver { return new BotZeroWorker(); } // 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 BotZeroWorker(); + public static synchronized Worker getZeroWorker(){ return new BotZeroWorker(); } + + public static synchronized BotSystemWorker getSystemWorker(String serverName){ + return systemLogWorkerMap.get(serverName); } + private static Worker validateConstancy(Worker worker, String srv, String chan){ // synchronized? if (worker.isConsistent()){ return worker; diff --git a/src/main/java/InnaIrcBot/LogDriver/BotFilesWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotFilesWorker.java index 82dd6e7..7b8d077 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotFilesWorker.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotFilesWorker.java @@ -40,7 +40,7 @@ public class BotFilesWorker implements Worker { return; // consistent = false; } if (!dir.exists()) { - System.out.println("BotFilesWorker (@"+server+")->constructor() failed:\n\tUnable to create directory to store files: " + dirLocation); //TODO: notify requester + System.out.println("BotFilesWorker (@"+server+")->constructor() failed:\n\tUnable to create directory to store files: " + dirLocation); return; } diff --git a/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java index 840e041..220c8ae 100644 --- a/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java +++ b/src/main/java/InnaIrcBot/LogDriver/BotMongoWorker.java @@ -25,8 +25,6 @@ public class BotMongoWorker implements Worker { //TODO consi private MongoCollection collection; private boolean consistent = false; - private boolean isItSystemThread = false; - public BotMongoWorker(String ircServer, String[] driverParameters, String channel){ this.ircServer = ircServer; @@ -49,9 +47,6 @@ public class BotMongoWorker implements Worker { //TODO consi else return; // consistent = false - if (channel.equals("system")) // Set ircServer variable only if it's 'system' log thread. - this.isItSystemThread = true; - if (!serversMap.containsKey(ircServer)){ /* // Leave this validations for better times. CommandListener mongoCommandListener = new CommandListener() { @@ -132,6 +127,25 @@ public class BotMongoWorker implements Worker { //TODO consi consistent = false; // no need to close() obviously } + + if (consistent){ + ThingToCloseOnDie thing = new ThingToCloseOnDie() { + @Override + public void die() { + if (serversMap.containsKey(ircServer)) { + try { + serversMap.get(ircServer).close(); + serversMap.remove(ircServer); + }catch (Exception e){ + System.out.println("ThingToCloseOnDie: something went wrong when tried to close MongoDB connection\t\n"+e); + } + } + } + }; + + BotDriver.getSystemWorker(ircServer).registerInSystemWorker(thing); + } + } @Override @@ -194,13 +208,6 @@ public class BotMongoWorker implements Worker { //TODO consi @Override public void close() { - // If ircServer != null then it's system thread and when it's interrupted we have to close connection to DB for used server - // And remove it from HashMap - if (this.isItSystemThread && serversMap.containsKey(ircServer)) { - serversMap.get(ircServer).close(); - serversMap.remove(ircServer); - //System.out.println("BotMongoWorker (@"+this.ircServer+")->close()"); // expected exit - } consistent = false; } private void close(String server) { diff --git a/src/main/java/InnaIrcBot/LogDriver/BotSystemWorker.java b/src/main/java/InnaIrcBot/LogDriver/BotSystemWorker.java new file mode 100644 index 0000000..390a3ea --- /dev/null +++ b/src/main/java/InnaIrcBot/LogDriver/BotSystemWorker.java @@ -0,0 +1,106 @@ +package InnaIrcBot.LogDriver; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +public class BotSystemWorker implements SystemWorker{ + + private FileWriter fileWriter; + private DateTimeFormatter dateFormat; + private ThingToCloseOnDie thingToCloseOnDie; // call .die() method of this classes when this (system log class) dies. + + String ircServer; + + private boolean consistent = false; + + public BotSystemWorker(String ircServer, String appLogDir){ + this.ircServer = ircServer; + this.dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss"); + + + if (appLogDir.isEmpty()) { + if (System.getProperty("os.name").toLowerCase().startsWith("win")) { + appLogDir = System.getProperty("user.home")+ File.separator + +"AppData"+File.separator + +"Local"+File.separator + +"InnaIrcBot"+File.separator; + } else { + appLogDir = "/var/log/innaircbot/"; + } + } + if (!appLogDir.endsWith(File.separator)) + appLogDir = appLogDir+File.separator; + + appLogDir = appLogDir+ircServer; + File logFile = new File(appLogDir); + try { + logFile.getParentFile().mkdirs(); + } catch (SecurityException e){ + System.out.println("BotSystemWorker (@"+ircServer+")->constructor() failed. Unable to create sub-directory(-ies) to store logs file ("+appLogDir+"):\n\t"+e); + return; // Consistent = false + } + if (!logFile.getParentFile().exists()) { + System.out.println("BotSystemWorker (@"+ircServer+")->constructor() failed:\n\tUnable to create sub-directory(-ies) to store log file: " + appLogDir); + return; + } + try { + this.fileWriter = new FileWriter(logFile, true); + consistent = true; + } catch (IOException oie){ + System.out.println("BotSystemWorker (@"+ircServer+")->constructor() failed:\n\tUnable to open file to store logs: " + appLogDir); + } + } + + private String genDate(){ + return "["+ LocalTime.now().format(dateFormat)+"] "; + } + + @Override + public void logAdd(String event, String initiatorArg, String messageArg) { + if (consistent) { + try { + fileWriter.write(genDate() + event + " " + initiatorArg + " " + messageArg + "\n"); + fileWriter.flush(); + } catch (IOException e) { + System.out.println("BotSystemWorker (@" + ircServer + ")->logAdd() failed\n\tUnable to write logs of because of internal failure in LocalTime representation."); + //this.close(); + consistent = false; + } catch (NullPointerException npe) { + System.out.println("BotSystemWorker (@" + ircServer + ")->logAdd() failed\n\tUnable to write logs of because file descriptor already closed/was not opened."); + consistent = false; + } catch (Exception unknowne) { // ??? No ideas. Just in case. Consider removing. + System.out.println("BotSystemWorker (@" + ircServer + ")->logAdd() failed\n\tUnable to write logs of because of exception:\n\t" + unknowne); + //this.close(); + consistent = false; + } + } + else { + System.out.println(genDate() + event + " " + initiatorArg + " " + messageArg + "\n"); + } + } + + @Override + public void registerInSystemWorker(ThingToCloseOnDie thing){ + if (this.thingToCloseOnDie == null){ // only one needed + this.thingToCloseOnDie = thing; + } + } + + @Override + public void close() { + if (thingToCloseOnDie != null) + thingToCloseOnDie.die(); + if (fileWriter != null) { + try { + fileWriter.close(); + } + catch (java.io.IOException e){ + System.out.println("BotSystemWorker (@"+ircServer+")->close() failed\n\tUnable to properly close logs file."); // Live with it. + } + } + consistent = false; + } +} diff --git a/src/main/java/InnaIrcBot/LogDriver/SystemWorker.java b/src/main/java/InnaIrcBot/LogDriver/SystemWorker.java new file mode 100644 index 0000000..00cc001 --- /dev/null +++ b/src/main/java/InnaIrcBot/LogDriver/SystemWorker.java @@ -0,0 +1,12 @@ +package InnaIrcBot.LogDriver; + +public interface SystemWorker { + + void registerInSystemWorker(ThingToCloseOnDie thing); + + void logAdd(String event, + String initiatorArg, + String messageArg); + + void close(); +} diff --git a/src/main/java/InnaIrcBot/LogDriver/ThingToCloseOnDie.java b/src/main/java/InnaIrcBot/LogDriver/ThingToCloseOnDie.java new file mode 100644 index 0000000..0a5645d --- /dev/null +++ b/src/main/java/InnaIrcBot/LogDriver/ThingToCloseOnDie.java @@ -0,0 +1,5 @@ +package InnaIrcBot.LogDriver; + +public interface ThingToCloseOnDie { + void die(); +} diff --git a/src/main/java/InnaIrcBot/ProvidersConsumers/DataProvider.java b/src/main/java/InnaIrcBot/ProvidersConsumers/DataProvider.java index a67a591..d3575d8 100644 --- a/src/main/java/InnaIrcBot/ProvidersConsumers/DataProvider.java +++ b/src/main/java/InnaIrcBot/ProvidersConsumers/DataProvider.java @@ -69,7 +69,7 @@ public class DataProvider implements Runnable { public void run(){ if (!ableToRun || !this.initConnection(rawStreamReader) - || !BotDriver.setLogDriver(serverName, configFile.getLogDriver(), configFile.getLogDriverParameters())) { //Prepare logDriver for using in threads. + || !BotDriver.setLogDriver(serverName, configFile.getLogDriver(), configFile.getLogDriverParameters(), configFile.getApplicationLogDir())) { //Prepare logDriver for using in threads. this.close(); return; } diff --git a/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java b/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java index ecaca32..63433c5 100644 --- a/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java +++ b/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java @@ -4,7 +4,7 @@ import InnaIrcBot.Commanders.PrivateMsgCommander; import InnaIrcBot.Config.StorageFile; import InnaIrcBot.GlobalData; import InnaIrcBot.LogDriver.BotDriver; -import InnaIrcBot.LogDriver.Worker; +import InnaIrcBot.LogDriver.BotSystemWorker; import java.io.*; import java.nio.charset.StandardCharsets; @@ -18,7 +18,7 @@ import java.util.regex.Pattern; public class SystemConsumer implements Runnable{ private BufferedReader reader; - private Worker writerWorker; + private BotSystemWorker writerWorker; private String nick; private String serverName; private Map channelsMap; @@ -29,9 +29,8 @@ public class SystemConsumer implements Runnable{ private PrivateMsgCommander commander; SystemConsumer(BufferedReader streamReader, String userNick, Map map, StorageFile storage) { - - this.writerWorker = BotDriver.getWorker(storage.getServerName(), "system"); - + //this.writerWorker = BotDriver.getWorker(storage.getServerName(), "system"); + this.writerWorker = BotDriver.getSystemWorker(storage.getServerName()); this.nick = userNick; this.serverName = storage.getServerName(); this.channelsMap = map; @@ -76,14 +75,15 @@ public class SystemConsumer implements Runnable{ if (getProxy(dataStrings[0], dataStrings[1], dataStrings[2])) continue; // TODO: check this. Continue is fair? - if (dataStrings[0].equals("PRIVMSG") && dataStrings[2].indexOf("\u0001") < dataStrings[2].lastIndexOf("\u0001")) - replyCTCP(dataStrings[1], dataStrings[2].substring(dataStrings[2].indexOf(":")+1)); - else if (Pattern.matches("(^[0-9]{3}$)|(^NICK$)|(^JOIN$)", dataStrings[0])){ + if (dataStrings[0].equals("PRIVMSG") && dataStrings[2].indexOf("\u0001") < dataStrings[2].lastIndexOf("\u0001")) { + replyCTCP(simplifyNick(dataStrings[1]), dataStrings[2].substring(dataStrings[2].indexOf(":") + 1)); + } + else if (Pattern.matches("(^[0-9]{3}$)|(^NICK$)|(^JOIN$)|(^QUIT$)", dataStrings[0])){ handleNumeric(dataStrings[0], dataStrings[1], dataStrings[2]); } else if (dataStrings[0].equals("PRIVMSG")) { commander.receiver(dataStrings[1], dataStrings[2].replaceAll("^.+?:", "").trim()); - writerWorker.logAdd("[system]", "PRIVMSG sent to", "commander"); + writerWorker.logAdd("[system]", "PRIVMSG from "+dataStrings[1]+" received: ", dataStrings[2].replaceAll("^.+?:", "").trim()); } else if (dataStrings[0].equals("INNA")) { String[] splitter; @@ -123,30 +123,32 @@ public class SystemConsumer implements Runnable{ } } - private void replyCTCP(String sender, String message){ + private void replyCTCP(String sender, String message){ // got simplified nick if (message.equals("\u0001VERSION\u0001")){ - StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :\u0001VERSION "+ GlobalData.getAppVersion()+"\u0001"); - writerWorker.logAdd("[system]", "catch/handled CTCP VERSION from", simplifyNick(sender)); - System.out.println(sender+" "+message); - System.out.println("NOTICE "+simplifyNick(sender)+" \u0001VERSION "+ GlobalData.getAppVersion()+"\u0001"); + StreamProvider.writeToStream(serverName,"NOTICE "+sender+" :\u0001VERSION "+ GlobalData.getAppVersion()+"\u0001"); + writerWorker.logAdd("[system]", "catch/handled CTCP VERSION from", sender); + //System.out.println(sender+" "+message); + //System.out.println("NOTICE "+sender+" \u0001VERSION "+ GlobalData.getAppVersion()+"\u0001"); } else if (message.startsWith("\u0001PING ") && message.endsWith("\u0001")){ - StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :"+message); - writerWorker.logAdd("[system]", "catch/handled CTCP PING from", simplifyNick(sender)); - //System.out.println(":"+simplifyNick(sender)+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" "+message); + StreamProvider.writeToStream(serverName,"NOTICE "+sender+" :"+message); + writerWorker.logAdd("[system]", "catch/handled CTCP PING from", sender); + //System.out.println(":"+sender+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" "+message); } else if (message.equals("\u0001CLIENTINFO\u0001")){ - StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :\u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO\u0001"); - writerWorker.logAdd("[system]", "catch/handled CTCP CLIENTINFO from", simplifyNick(sender)); - //System.out.println(":"+simplifyNick(sender)+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" \u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO\u0001"); + StreamProvider.writeToStream(serverName,"NOTICE "+sender+" :\u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO\u0001"); + writerWorker.logAdd("[system]", "catch/handled CTCP CLIENTINFO from", sender); + //System.out.println(":"+sender+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" \u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO\u0001"); } else if (message.equals("\u0001TIME\u0001")){ - StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :\u0001TIME "+ ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\u0001"); - writerWorker.logAdd("[system]", "catch/handled CTCP TIME from", simplifyNick(sender)); - //System.out.println(":"+simplifyNick(sender)+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" \u0001TIME "+ ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\u0001"); - } else - writerWorker.logAdd("[system]", "catch CTCP request \""+message+"\" from ", simplifyNick(sender)); + StreamProvider.writeToStream(serverName,"NOTICE "+sender+" :\u0001TIME "+ ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\u0001"); + writerWorker.logAdd("[system]", "catch/handled CTCP TIME from", sender); + //System.out.println(":"+sender+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" \u0001TIME "+ ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\u0001"); + } + else + writerWorker.logAdd("[system]", "catch unknown CTCP request \""+message+"\" from ", sender); } + private String simplifyNick(String nick){ return nick.replaceAll("!.*$",""); } @@ -204,7 +206,7 @@ public class SystemConsumer implements Runnable{ case "NICK": if (sender.startsWith(nick+"!")) { nick = message.trim(); - writerWorker.logAdd("[system]", "catch/handled own NICK change from:", sender+" to: "+message); + writerWorker.logAdd("[system]", "catch own NICK change from:", sender+" to: "+message); } break; case "JOIN": @@ -212,10 +214,11 @@ public class SystemConsumer implements Runnable{ proxyAList.put(message, new ArrayList<>()); // Add new channel name to proxy watch-list proxyAList.get(message).add(eventNum+" "+sender+" "+message); // Add message to array linked this.proxyRequired = true; // Ask for proxy validators + writerWorker.logAdd("[system]", "joined to channel ", "message"); } break; default: - writerWorker.logAdd("[system]", "catch: "+eventNum+" from: "+sender+" :",message); + writerWorker.logAdd("[system]", "catch: "+eventNum+" from: "+sender+" :",message); // TODO: QUIT comes here. Do something. break; } } diff --git a/src/main/java/Temporary/DriverTestFiles.java b/src/main/java/Temporary/DriverTestFiles.java index b3df7ea..550551b 100644 --- a/src/main/java/Temporary/DriverTestFiles.java +++ b/src/main/java/Temporary/DriverTestFiles.java @@ -6,7 +6,7 @@ import InnaIrcBot.LogDriver.Worker; public class DriverTestFiles { public static void main(String[] args){ - if (BotDriver.setLogDriver("irc.tomsk.net", "files", new String[]{"/tmp/logs/"})) + if (BotDriver.setLogDriver("irc.tomsk.net", "files", new String[]{"/tmp/logs/"}, "/tmp/appLogs/")) System.out.println("DRVT_Files: Successful driver initiation"); else { System.out.println("DRVT_Files: Failed driver initiation"); diff --git a/src/main/java/Temporary/DriverTestMongo.java b/src/main/java/Temporary/DriverTestMongo.java index ad89701..de09782 100644 --- a/src/main/java/Temporary/DriverTestMongo.java +++ b/src/main/java/Temporary/DriverTestMongo.java @@ -9,7 +9,8 @@ public class DriverTestMongo { if (BotDriver.setLogDriver("irc.tomsk.net", "MongoDB", new String[]{"192.168.1.186:27017", "irc", "loper", - "password"})) + "password"}, + "/tmp/appLogs/")) System.out.println("DRVT_Mongo:Successful driver initiation"); else { System.out.println("DRVT_Mongo:Failed driver initiation"); diff --git a/src/main/java/Temporary/DriverTestSQLite.java b/src/main/java/Temporary/DriverTestSQLite.java index 7b0c674..91cf562 100644 --- a/src/main/java/Temporary/DriverTestSQLite.java +++ b/src/main/java/Temporary/DriverTestSQLite.java @@ -6,7 +6,7 @@ import InnaIrcBot.LogDriver.Worker; public class DriverTestSQLite { public static void main(String[] args){ - if (BotDriver.setLogDriver("irc.tomsk.net", "SQLite", new String[]{"/tmp/logs/mylogs"})) + if (BotDriver.setLogDriver("irc.tomsk.net", "SQLite", new String[]{"/tmp/logs/mylogs"}, "/tmp/appLogs/")) System.out.println("DRVT_SQLite:Successful driver initiation"); else { System.out.println("DRVT_SQLite:Failed driver initiation"); diff --git a/src/main/java/Temporary/StorageFileTest.java b/src/main/java/Temporary/StorageFileTest.java index abe085d..25ad336 100644 --- a/src/main/java/Temporary/StorageFileTest.java +++ b/src/main/java/Temporary/StorageFileTest.java @@ -19,6 +19,7 @@ public class StorageFileTest { "", new String[]{null}, "", + "", "" );