Merge pull request #1 from developersu/development

Development
This commit is contained in:
Dmitry Isaenko 2019-01-27 06:38:23 +03:00 committed by GitHub
commit 5e032eef41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 820 additions and 172 deletions

View file

@ -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"
}

View file

@ -1,6 +1,6 @@
# InnaIrcBot # InnaIrcBot
Another one IRC bot in deep beta. Another one IRC bot in deep-deep beta.
## Usage ## Usage
` -c, --configuration <name.config> [<name1.config> ...] Read Config` ` -c, --configuration <name.config> [<name1.config> ...] Read Config`
@ -16,6 +16,7 @@ Another one IRC bot in deep beta.
"logDriver" could be "Files", "SQLite" or "Zero" "logDriver" could be "Files", "SQLite" or "Zero"
* Files - log everything to files using /yourPathSet/serverName/#chanelName_YYYY-MM-DD.txt format. * 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. * SQLite - use /yourPathSet/server.db (or /yourPathSet/yourFileName.db) sqlite file.
* MongoDB - write files to MongoDB. See ConfigurationExamples folder.
## License ## License
Source code spreads under the GNU General Public License v3 or higher. Please see LICENSE file. Source code spreads under the GNU General Public License v3 or higher. Please see LICENSE file.
@ -23,6 +24,7 @@ Source code spreads under the GNU General Public License v3 or higher. Please se
Used libraries: Used libraries:
* GSON: https://github.com/google/gson * GSON: https://github.com/google/gson
* sqliteJDBC: https://bitbucket.org/xerial/sqlite-jdbc * sqliteJDBC: https://bitbucket.org/xerial/sqlite-jdbc
* mongodb-driver-sync: https://mongodb.github.io/mongo-java-driver/3.9/
## TODO: ## TODO:
@ -30,9 +32,9 @@ Used libraries:
- [ ] Code refactoring - [ ] Code refactoring
- [ ] QA: good regression testing - [ ] QA: good regression testing
- [x] CI/CD Jenkins - [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) - [ ] 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 - [ ] Logs backend worker for redis/redis node
- [ ] Re-implement connection routine - [ ] Re-implement connection routine
- [ ] Availability to run scripts @ 'ChanelCommander' - [ ] Availability to run scripts @ 'ChanelCommander'
@ -41,3 +43,6 @@ Used libraries:
- [ ] Deep configuration files validation - [ ] Deep configuration files validation
- [x] Maven ~~or Gradle~~ build - [x] Maven ~~or Gradle~~ build
- [ ] ncurses-like or/and GUI configuration files (server/chanel setting) editor - [ ] 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 (partly implemented)

View file

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>loper</groupId> <groupId>loper</groupId>
<artifactId>InnaIrcBot</artifactId> <artifactId>InnaIrcBot</artifactId>
<version>0.3-SNAPSHOT</version> <version>0.4-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>InnaIrcBot</name> <name>InnaIrcBot</name>
@ -24,6 +24,12 @@
<version>2.8.5</version> <version>2.8.5</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>3.9.1</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>
<build><plugins> <build><plugins>
<plugin> <plugin>

View file

@ -11,6 +11,7 @@ public class BotStart {
//TODO: flood control //TODO: flood control
//TODO: setDaemon(true) //TODO: setDaemon(true)
//TODO: multiple connections to one server not allowed //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){ public static void main(String[] args){
if (args.length != 0) { if (args.length != 0) {

View file

@ -133,6 +133,10 @@ public class ChanelCommander implements Runnable {
whatToSendRaw.append(cmdOrMsg[i]); whatToSendRaw.append(cmdOrMsg[i]);
StreamProvider.writeToStream(server, whatToSendRaw.toString()); //TODO 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: default:
i++; 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){ private void msgAction(String[] messages, String who, boolean sendToPrivate){
StringBuilder executiveStr = new StringBuilder(); StringBuilder executiveStr = new StringBuilder();
executiveStr.append("PRIVMSG "); executiveStr.append("PRIVMSG ");

View file

@ -25,7 +25,6 @@ public class PrivateMsgCommander { // T
if (cmd.length > 1) if (cmd.length > 1)
cmd[1] = cmd[1].trim(); cmd[1] = cmd[1].trim();
switch (cmd[0]){ switch (cmd[0]){
case "tell": case "tell":
if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) { if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) {
@ -290,7 +289,7 @@ public class PrivateMsgCommander { // T
} }
} }
private void kickban(String chanel, String user, String reason){ private void kickban(String chanel, String user, String reason){
cmode(chanel, "+b", simplifyNick(user)+"*!*@*"); ban(chanel, user);
kick(chanel, user, reason); kick(chanel, user, reason);
} }
private void voice(String chanel, String user){ private void voice(String chanel, String user){

View file

@ -16,6 +16,7 @@ public class StorageFile {
private final String[] logDriverParameters; private final String[] logDriverParameters;
private final String botAdministratorPassword; private final String botAdministratorPassword;
private final String chanelConfigurationsPath; private final String chanelConfigurationsPath;
private final String applicationLogDir;
public String getServerName() { return serverName; } public String getServerName() { return serverName; }
public int getServerPort() { return serverPort; } public int getServerPort() { return serverPort; }
@ -32,6 +33,7 @@ public class StorageFile {
public String[] getLogDriverParameters() { return logDriverParameters; } public String[] getLogDriverParameters() { return logDriverParameters; }
public String getBotAdministratorPassword() { return botAdministratorPassword; } public String getBotAdministratorPassword() { return botAdministratorPassword; }
public String getChanelConfigurationsPath() { return chanelConfigurationsPath; } public String getChanelConfigurationsPath() { return chanelConfigurationsPath; }
public String getApplicationLogDir() { return applicationLogDir; }
public StorageFile(String serverName, public StorageFile(String serverName,
int serverPort, int serverPort,
@ -47,7 +49,8 @@ public class StorageFile {
String logDriver, String logDriver,
String[] logDriverParameters, String[] logDriverParameters,
String botAdministratorPassword, String botAdministratorPassword,
String chanelConfigurationsPath){ String chanelConfigurationsPath,
String applicationLogDir){
this.serverName = serverName; this.serverName = serverName;
this.serverPort = serverPort; this.serverPort = serverPort;
this.serverPass = serverPass; this.serverPass = serverPass;
@ -63,5 +66,6 @@ public class StorageFile {
this.logDriverParameters = logDriverParameters; this.logDriverParameters = logDriverParameters;
this.botAdministratorPassword = botAdministratorPassword; this.botAdministratorPassword = botAdministratorPassword;
this.chanelConfigurationsPath = chanelConfigurationsPath; this.chanelConfigurationsPath = chanelConfigurationsPath;
this.applicationLogDir = applicationLogDir;
} }
} }

View file

@ -78,7 +78,8 @@ public class StorageReader {
"Files", "Files",
new String[] {System.getProperty("user.home")}, new String[] {System.getProperty("user.home")},
"pswd", "pswd",
System.getProperty("user.home") System.getProperty("user.home"),
"/var/logs/"
); );
Gson writingStorageObject = new GsonBuilder().setPrettyPrinting().create(); Gson writingStorageObject = new GsonBuilder().setPrettyPrinting().create();

View file

@ -1,7 +1,7 @@
package InnaIrcBot; package InnaIrcBot;
public class GlobalData { public class GlobalData {
private static final String version = "InnaIrcBot v0.3 \"Карелия\""; private static final String version = "InnaIrcBot v0.4 \"Карские Ворота\"";
public static synchronized String getAppVersion(){ public static synchronized String getAppVersion(){
return version; return version;
} }

View file

@ -4,17 +4,20 @@ import java.util.HashMap;
public class BotDriver { public class BotDriver {
private static HashMap<String, String[][]> serverDriver = new HashMap<>(); private static HashMap<String, String[][]> serverDriver = new HashMap<>();
private static HashMap<String, BotSystemWorker> systemLogWorkerMap = new HashMap<>();
/** /**
* Define driver for desired server * Define driver for desired server
* */ * */
// TODO: add proxy worker for using with multiple drivers // 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()) { if (!driver.isEmpty() && driverParams != null && driverParams.length > 0 && driverParams[0] != null && !driverParams[0].isEmpty()) {
String[][] drvAndParams = { String[][] drvAndParams = {
{driver}, {driver},
driverParams driverParams
}; };
serverDriver.put(serverName, drvAndParams); serverDriver.put(serverName, drvAndParams);
systemLogWorkerMap.put(serverName, new BotSystemWorker(serverName, applicationLogDir));
return true; return true;
} }
else else
@ -22,20 +25,44 @@ public class BotDriver {
} }
public static synchronized Worker getWorker(String serverName, String chanelName){ public static synchronized Worker getWorker(String serverName, String chanelName){
if (serverDriver.containsKey(serverName)) { if (serverDriver.containsKey(serverName)) {
switch (serverDriver.get(serverName)[0][0]) { switch (serverDriver.get(serverName)[0][0].toLowerCase()) {
case "Files": case "files":
return new BotFilesWorker(serverName, serverDriver.get(serverName)[1], chanelName); BotFilesWorker botFilesWorker = new BotFilesWorker(serverName, serverDriver.get(serverName)[1], chanelName);
case "SQLite": return validateConstancy(botFilesWorker, serverName, chanelName);
return new BotSQLiteWorker(serverName, serverDriver.get(serverName)[1], chanelName); case "sqlite":
case "Zero": 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);
return validateConstancy(botMongoWorker, serverName, chanelName);
case "zero":
return new BotZeroWorker(); return new BotZeroWorker();
default: 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] +serverDriver.get(serverName)[0][0]
+"\".Using \"ZeroWorker\"."); +"\".Using \"ZeroWorker\".");
return new BotZeroWorker(); 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(); }
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;
}
else {
System.out.println("BotDriver->validateConstancy(): Unable to use "
+worker.getClass().getSimpleName()+" for "+srv+"/"+chan
+". Using ZeroWorker instead.");
return new BotZeroWorker();
}
} }
} }

View file

@ -16,31 +16,35 @@ public class BotFilesWorker implements Worker {
private LocalDate fileWriterDay; private LocalDate fileWriterDay;
private FileWriter fileWriter; private FileWriter fileWriter;
public BotFilesWorker(String server, String[] driverParameters, String channel){ private String ircServer; // hold for debug only
if (System.getProperty("os.name").startsWith("Windows")){
channel = channel.replaceAll("\",",",");
}
else {
channel = channel.replaceAll("/",",");
}
driverParameters[0] = driverParameters[0].trim(); //Consider parameters[0] as dirLocation public BotFilesWorker(String server, String[] driverParameters, String channel){
String dirLocation; ircServer = server;
if (driverParameters[0].endsWith(File.separator)) dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
dirLocation = driverParameters[0]+server;
channel = channel.replaceAll(File.separator, ",");
String dirLocation = driverParameters[0].trim();
if (dirLocation.endsWith(File.separator))
dirLocation = dirLocation+server;
else else
dirLocation = driverParameters[0]+File.separator+server; dirLocation = dirLocation+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;
}
this.filePath = dirLocation+File.separator+channel; this.filePath = dirLocation+File.separator+channel;
dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss"); File dir = new File(dirLocation);
if (resetFileWriter(false)) try {
this.consistent = true; 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);
return;
}
this.consistent = resetFileWriter(false);
} }
private boolean resetFileWriter(boolean reassign){ private boolean resetFileWriter(boolean reassign){
@ -52,7 +56,7 @@ public class BotFilesWorker implements Worker {
return true; return true;
} }
catch (java.io.IOException e){ 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; return false;
} }
} }
@ -66,7 +70,7 @@ public class BotFilesWorker implements Worker {
* argument[1] should be always 'subject' * argument[1] should be always 'subject'
* */ * */
@Override @Override
public void logAdd(String event, String initiatorArg, String messageArg) { public boolean logAdd(String event, String initiatorArg, String messageArg) {
switch (event){ switch (event){
case "PRIVMSG": case "PRIVMSG":
PRIVMSG(initiatorArg, messageArg); 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 this.prettyPrint("["+LocalTime.now().format(dateFormat)+"] "+event+" "+initiatorArg+" "+messageArg+"\n"); // TODO: QA @ big data
break; break;
} }
} return consistent;
@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.
}
} }
private void prettyPrint(String string){ private void prettyPrint(String string){
if (LocalDate.now().isAfter(fileWriterDay)) //if (consistent) { // could be not-opened
resetFileWriter(true);
try { try {
if (LocalDate.now().isAfter(fileWriterDay)) {
if (!resetFileWriter(true)) {
this.close(); // Error message already printed
return;
}
}
fileWriter.write(string); fileWriter.write(string);
fileWriter.flush(); fileWriter.flush();
} catch (IOException e) { } 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."); 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; 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(){ private String genDate(){
return "["+LocalTime.now().format(dateFormat)+"] "; return "["+LocalTime.now().format(dateFormat)+"] ";
@ -160,4 +168,16 @@ public class BotFilesWorker implements Worker {
private void TOPIC(String initiatorArg, String messageArg) { private void TOPIC(String initiatorArg, String messageArg) {
this.prettyPrint(genDate()+"-!- "+getUserNameAndHost(initiatorArg)+"has changed topic to: "+messageArg.replaceAll("^.+?:", "")+"\n"); 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;
}
} }

View file

@ -0,0 +1,221 @@
package InnaIrcBot.LogDriver;
import com.mongodb.*;
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;
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 { //TODO consider skipping checks if server already added.
private static Map<String, MongoClient> serversMap = Collections.synchronizedMap(new HashMap<String, MongoClient>());
private String ircServer;
private MongoCollection<Document> collection;
private boolean consistent = false;
public BotMongoWorker(String ircServer, String[] driverParameters, String channel){
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
return; // consistent = false
if (!serversMap.containsKey(ircServer)){
/* // Leave this validations for better times.
CommandListener mongoCommandListener = new CommandListener() {
@Override
public void commandStarted(CommandStartedEvent commandStartedEvent) {
System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandStarted");
}
@Override
public void commandSucceeded(CommandSucceededEvent commandSucceededEvent) {
System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandSucceeded");
}
@Override
public void commandFailed(CommandFailedEvent commandFailedEvent) {
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 (@"+ircServer+"): ServerListener: Server opened successfully: "+serverOpeningEvent.getServerId());
}
@Override
public void serverClosed(ServerClosedEvent serverClosedEvent) {
System.out.println("BotMongoWorker (@"+ircServer+"): ServerListener: Server has been closed");
}
@Override
public void serverDescriptionChanged(ServerDescriptionChangedEvent serverDescriptionChangedEvent) {
if (!serverDescriptionChangedEvent.getNewDescription().isOk()) {
close(ircServer); // ircServer recieved by constructor, not this.ircServer
System.out.println("BotMongoWorker (@"+ircServer+"): ServerListener: Server description changed (exception occurs): "
+ serverDescriptionChangedEvent.getNewDescription().getException());
}
}
};
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();
MongoClient mongoClient = MongoClients.create(MCS);
serversMap.put(ircServer, mongoClient);
}
MongoDatabase mongoDB = serversMap.get(ircServer).getDatabase(mongoDBName);
collection = mongoDB.getCollection(ircServer + channel);
Document ping = new Document("ping", 1);
//
try {
Document answer = mongoDB.runCommand(ping); // reports to monitor thread if some fuckups happens
if (answer.get("ok") == null || (Double)answer.get("ok") != 1.0d){
close(ircServer);
return;
}
consistent = true;
} catch (MongoCommandException mce){
System.out.println("BotMongoWorker (@"+this.ircServer+"): Command exception. Check if username/password set correctly.");
close(ircServer); // ircServer received by constructor, not this.ircServer
} catch (MongoTimeoutException mte) {
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.");
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
}
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
public boolean 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;
}
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
@Override
public boolean isConsistent() { return consistent; }
@Override
public void close() {
consistent = false;
}
private void close(String server) {
if (serversMap.containsKey(server)) {
serversMap.get(server).close();
serversMap.remove(server);
System.out.println("BotMongoWorker (@"+this.ircServer+")->close() [forced by listeners]");
}
consistent = false;
}
}

View file

@ -11,16 +11,24 @@ public class BotSQLiteWorker implements Worker {
private Connection connection; private Connection connection;
private boolean consistent = false; private boolean consistent = false;
private PreparedStatement preparedStatement; private PreparedStatement preparedStatement;
private String ircServer;
/** /**
* Don't even think of changing this balalaika. * 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(); driverParameters[0] = driverParameters[0].trim();
File dir = new File(driverParameters[0]); File dir = new File(driverParameters[0]);
dir.mkdirs(); try {
if (!dir.exists()) { 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.
System.out.println("Unable to create directory to store DB file: " + driverParameters[0]); //TODO: notify requester } catch (Exception e){
this.consistent = false; 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; String connectionURL;
if (driverParameters[0].endsWith(File.separator)) if (driverParameters[0].endsWith(File.separator))
@ -28,7 +36,7 @@ public class BotSQLiteWorker implements Worker {
else else
connectionURL = "jdbc:sqlite:"+driverParameters[0]+File.separator+server+".db"; 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 { try {
SQLiteConfig sqlConfig = new SQLiteConfig(); SQLiteConfig sqlConfig = new SQLiteConfig();
sqlConfig.setOpenMode(SQLiteOpenMode.NOMUTEX); //SQLITE_OPEN_NOMUTEX : multithreaded mode sqlConfig.setOpenMode(SQLiteOpenMode.NOMUTEX); //SQLITE_OPEN_NOMUTEX : multithreaded mode
@ -37,7 +45,7 @@ public class BotSQLiteWorker implements Worker {
if (connection != null){ if (connection != null){
// Create table if not created // Create table if not created
Statement statement = connection.createStatement(); 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," + " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
+ " unixtime INTEGER," + " unixtime INTEGER,"
+ " event TEXT," + " event TEXT,"
@ -48,7 +56,7 @@ public class BotSQLiteWorker implements Worker {
statement.executeUpdate(query); statement.executeUpdate(query);
// Check table representation // 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}; boolean[] schemaResultCheck = {false, false, false, false, false, false};
while (rs.next()) { 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. // Validating result: it table in DB have expected schema. If not, removing and recreating table.
for (boolean element: schemaResultCheck) { for (boolean element: schemaResultCheck) {
if (!element) { if (!element) {
System.out.println("BotSQLiteWorker: Found already existing table for channel with incoorect syntax: removing table and re-creating."); 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 \"" + safeChanName + "\";"); statement.executeUpdate("DROP TABLE \"" + channel + "\";");
statement.executeUpdate(query); statement.executeUpdate(query);
break; break;
} }
@ -125,17 +133,18 @@ public class BotSQLiteWorker implements Worker {
this.consistent = true; this.consistent = true;
this.preparedStatement = connection.prepareStatement( this.preparedStatement = connection.prepareStatement(
"INSERT INTO \""+safeChanName "INSERT INTO \""+channel
+"\" (unixtime, event, subject, message, object) " +"\" (unixtime, event, subject, message, object) "
+"VALUES (?, ?, ?, ?, ?);"); +"VALUES (?, ?, ?, ?, ?);");
} }
else { else {
System.out.println("BotSQLiteWorker (@"+server+")->constructor() failed:\n\t Connection to SQLite not established.");
this.consistent = false; this.consistent = false;
} }
} }
catch (SQLException e){ catch (SQLException e){
System.out.println("Internal issue: BotSQLiteWorker->constructor() failed\n\t"+e); System.out.println("BotSQLiteWorker (@"+server+")->constructor() failed:\n\t"+e);
this.consistent = false; this.consistent = false; // this.close();
} }
} }
@ -146,7 +155,7 @@ public class BotSQLiteWorker implements Worker {
public boolean isConsistent() {return consistent; } public boolean isConsistent() {return consistent; }
@Override @Override
public void logAdd(String event, String initiatorArg, String messageArg) { public boolean logAdd(String event, String initiatorArg, String messageArg) {
try { try {
preparedStatement.setLong(1, getDate()); preparedStatement.setLong(1, getDate());
preparedStatement.setString(2, event); preparedStatement.setString(2, event);
@ -168,24 +177,28 @@ public class BotSQLiteWorker implements Worker {
preparedStatement.setString(5, messageArg.replaceAll("^(.+?\\s){2}", "")); preparedStatement.setString(5, messageArg.replaceAll("^(.+?\\s){2}", ""));
break; break;
case "KICK": case "KICK":
preparedStatement.setString(4,messageArg.replaceAll("^.+?:", "")); preparedStatement.setString(4, messageArg.replaceAll("^.+?:", ""));
preparedStatement.setString(5,messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")); preparedStatement.setString(5, messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", ""));
break; break;
case "PRIVMSG": case "PRIVMSG":
preparedStatement.setString(4,messageArg.replaceAll("^:", "")); preparedStatement.setString(4, messageArg.replaceAll("^:", ""));
preparedStatement.setString(5,null); preparedStatement.setString(5,null);
break; break;
default: default:
preparedStatement.setString(4,messageArg); preparedStatement.setString(4, messageArg);
preparedStatement.setString(5,null); preparedStatement.setString(5,null);
break; break;
} }
preparedStatement.executeUpdate(); preparedStatement.executeUpdate();
} }
catch (SQLException e){ catch (SQLException sqle){
System.out.println("Internal issue: BotSQLiteWorker->logAdd() failed\n\t"+e); System.out.println("BotSQLiteWorker (@"+ircServer+")->logAdd() failed:\n\t"+sqle);
this.consistent = false; 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 @Override
@ -194,8 +207,9 @@ public class BotSQLiteWorker implements Worker {
//System.out.println("SQLite drier closed"); //System.out.println("SQLite drier closed");
this.connection.close(); this.connection.close();
} }
catch (SQLException e){ catch (SQLException | NullPointerException e){ //todo: consider redo
System.out.println("Internal issue: BotSQLiteWorker->close() failed\n\t" + e); System.out.println("BotSQLiteWorker (@"+ircServer+")->close() failed:\n\t" + e); // nothing to do here
} }
this.consistent = false;
} }
} }

View file

@ -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;
}
}

View file

@ -5,7 +5,7 @@ public class BotZeroWorker implements Worker{
public boolean isConsistent() {return true;} public boolean isConsistent() {return true;}
@Override @Override
public void logAdd(String event, String initiatorArg, String messageArg) {} public boolean logAdd(String event, String initiatorArg, String messageArg) { return true; }
@Override @Override
public void close() {} public void close() {}

View file

@ -0,0 +1,12 @@
package InnaIrcBot.LogDriver;
public interface SystemWorker {
void registerInSystemWorker(ThingToCloseOnDie thing);
void logAdd(String event,
String initiatorArg,
String messageArg);
void close();
}

View file

@ -0,0 +1,5 @@
package InnaIrcBot.LogDriver;
public interface ThingToCloseOnDie {
void die();
}

View file

@ -5,7 +5,7 @@ public interface Worker {
boolean isConsistent(); boolean isConsistent();
void logAdd(String event, boolean logAdd(String event,
String initiatorArg, String initiatorArg,
String messageArg); String messageArg);

View file

@ -54,13 +54,16 @@ public class ChanConsumer implements Runnable {
if (!trackUsers(dataStrings[0], dataStrings[1], dataStrings[2])) if (!trackUsers(dataStrings[0], dataStrings[1], dataStrings[2]))
continue; continue;
writerWorker.logAdd(dataStrings[0], dataStrings[1], dataStrings[2]);
// Send to chanel commander thread // Send to chanel commander thread
chanelCommanderPipe.println(data); chanelCommanderPipe.println(data);
chanelCommanderPipe.flush(); chanelCommanderPipe.flush();
//System.out.println("|"+dataStrings[0]+"|"+dataStrings[1]+"|"+dataStrings[2]+"|"); //System.out.println("|"+dataStrings[0]+"|"+dataStrings[1]+"|"+dataStrings[2]+"|");
//System.out.println("Thread: "+this.channelName +"\n\tArray:"+ userList); //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) { if (endThread) {
reader.close(); reader.close();
chanList.get(channelName).close(); chanList.get(channelName).close();
@ -69,7 +72,7 @@ public class ChanConsumer implements Runnable {
} }
} }
} catch (java.io.IOException e){ } 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(); writerWorker.close();
//Chanel commander thread's pipe should be closed //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 case "PRIVMSG": // most common, we don't have to handle anything else
return true; return true;
case "JOIN": case "JOIN":
addUsers(initiatorArg); addUsers(simplifyNick(initiatorArg));
return true; return true;
case "PART": case "PART":
delUsers(initiatorArg); delUsers(simplifyNick(initiatorArg)); // nick non-simple
return true; return true;
case "QUIT": // TODO fix: use regex case "QUIT":
if (userList.contains(initiatorArg.replaceAll("!.+$", ""))) { if (userList.contains(simplifyNick(initiatorArg))) {
delUsers(initiatorArg); delUsers(simplifyNick(initiatorArg)); // nick non-simple
return true; return true;
} else } else
return false; // user quit, but he/she is not in this channel return false; // user quit, but he/she is not in this channel
case "KICK": 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); StreamProvider.writeToStream(serverName, "JOIN " + channelName);
delUsers(subjectArg.substring(subjectArg.indexOf(" ") + 1, subjectArg.indexOf(" :"))); delUsers(subjectArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")); // nick already simplified
return true; return true;
case "NICK": case "NICK":
if (userList.contains(initiatorArg.replaceAll("!.+$", ""))) { if (userList.contains(simplifyNick(initiatorArg))) {
swapUsers(initiatorArg, subjectArg); swapUsers(simplifyNick(initiatorArg), subjectArg);
return true; return true;
} else { } else {
return false; // user changed nick, but he/she is not in this channel 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){ private void addUsers(String user){
if (!userList.contains(user.replaceAll("!.+$", ""))) if (!userList.contains(user))
userList.add(user.replaceAll("!.+$", "")); userList.add(user);
} }
private void delUsers(String user){ private void delUsers(String user){
if (user.replaceAll("!.+$", "").equals(nick)) { if (user.equals(nick)) {
endThread = true; endThread = true;
} }
userList.remove(user.replaceAll("!.+$", "")); userList.remove(user);
} }
private void swapUsers(String userNickOld, String userNickNew){ private void swapUsers(String userNickOld, String userNickNew){
userList.remove(userNickOld.replaceAll("!.+$", "")); userList.remove(userNickOld);
userList.add(userNickNew); userList.add(userNickNew);
if (userNickOld.replaceAll("!.+$", "").equals(nick)) if (userNickOld.equals(nick))
this.nick = userNickNew; this.nick = userNickNew;
} }
// Create ChanelCommander // Create ChanelCommander
@ -142,9 +145,19 @@ public class ChanConsumer implements Runnable {
return new PrintWriter(streamOut); return new PrintWriter(streamOut);
} catch (IOException e) { } 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; endThread = true;
return null; 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.");
}
}
} }

View file

@ -69,7 +69,7 @@ public class DataProvider implements Runnable {
public void run(){ public void run(){
if (!ableToRun || !this.initConnection(rawStreamReader) 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(); this.close();
return; return;
} }

View file

@ -4,7 +4,7 @@ import InnaIrcBot.Commanders.PrivateMsgCommander;
import InnaIrcBot.Config.StorageFile; import InnaIrcBot.Config.StorageFile;
import InnaIrcBot.GlobalData; import InnaIrcBot.GlobalData;
import InnaIrcBot.LogDriver.BotDriver; import InnaIrcBot.LogDriver.BotDriver;
import InnaIrcBot.LogDriver.Worker; import InnaIrcBot.LogDriver.BotSystemWorker;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -18,7 +18,7 @@ import java.util.regex.Pattern;
public class SystemConsumer implements Runnable{ public class SystemConsumer implements Runnable{
private BufferedReader reader; private BufferedReader reader;
private Worker writerWorker; private BotSystemWorker writerWorker;
private String nick; private String nick;
private String serverName; private String serverName;
private Map<String, PrintWriter> channelsMap; private Map<String, PrintWriter> channelsMap;
@ -29,7 +29,8 @@ public class SystemConsumer implements Runnable{
private PrivateMsgCommander commander; private PrivateMsgCommander commander;
SystemConsumer(BufferedReader streamReader, String userNick, Map<String, PrintWriter> map, StorageFile storage) { SystemConsumer(BufferedReader streamReader, String userNick, Map<String, PrintWriter> 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.nick = userNick;
this.serverName = storage.getServerName(); this.serverName = storage.getServerName();
this.channelsMap = map; this.channelsMap = map;
@ -65,7 +66,7 @@ public class SystemConsumer implements Runnable{
private void setMainRoutine(){ private void setMainRoutine(){
String data; String data;
String dataStrings[]; String[] dataStrings;
try { try {
while ((data = reader.readLine()) != null) { while ((data = reader.readLine()) != null) {
dataStrings = data.split(" ",3); dataStrings = data.split(" ",3);
@ -74,14 +75,15 @@ public class SystemConsumer implements Runnable{
if (getProxy(dataStrings[0], dataStrings[1], dataStrings[2])) if (getProxy(dataStrings[0], dataStrings[1], dataStrings[2]))
continue; // TODO: check this. Continue is fair? continue; // TODO: check this. Continue is fair?
if (dataStrings[0].equals("PRIVMSG") && dataStrings[2].indexOf("\u0001") < dataStrings[2].lastIndexOf("\u0001")) if (dataStrings[0].equals("PRIVMSG") && dataStrings[2].indexOf("\u0001") < dataStrings[2].lastIndexOf("\u0001")) {
replyCTCP(dataStrings[1], dataStrings[2].substring(dataStrings[2].indexOf(":")+1)); replyCTCP(simplifyNick(dataStrings[1]), dataStrings[2].substring(dataStrings[2].indexOf(":") + 1));
else if (Pattern.matches("(^[0-9]{3}$)|(^NICK$)|(^JOIN$)", dataStrings[0])){ }
else if (Pattern.matches("(^[0-9]{3}$)|(^NICK$)|(^JOIN$)|(^QUIT$)", dataStrings[0])){
handleNumeric(dataStrings[0], dataStrings[1], dataStrings[2]); handleNumeric(dataStrings[0], dataStrings[1], dataStrings[2]);
} }
else if (dataStrings[0].equals("PRIVMSG")) { else if (dataStrings[0].equals("PRIVMSG")) {
commander.receiver(dataStrings[1], dataStrings[2].replaceAll("^.+?:", "").trim()); 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")) { else if (dataStrings[0].equals("INNA")) {
String[] splitter; String[] splitter;
@ -121,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")){ if (message.equals("\u0001VERSION\u0001")){
StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :\u0001VERSION "+ GlobalData.getAppVersion()+"\u0001"); StreamProvider.writeToStream(serverName,"NOTICE "+sender+" :\u0001VERSION "+ GlobalData.getAppVersion()+"\u0001");
writerWorker.logAdd("[system]", "catch/handled CTCP VERSION from", simplifyNick(sender)); writerWorker.logAdd("[system]", "catch/handled CTCP VERSION from", sender);
System.out.println(sender+" "+message); //System.out.println(sender+" "+message);
System.out.println("NOTICE "+simplifyNick(sender)+" \u0001VERSION "+ GlobalData.getAppVersion()+"\u0001"); //System.out.println("NOTICE "+sender+" \u0001VERSION "+ GlobalData.getAppVersion()+"\u0001");
} }
else if (message.startsWith("\u0001PING ") && message.endsWith("\u0001")){ else if (message.startsWith("\u0001PING ") && message.endsWith("\u0001")){
StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :"+message); StreamProvider.writeToStream(serverName,"NOTICE "+sender+" :"+message);
writerWorker.logAdd("[system]", "catch/handled CTCP PING from", simplifyNick(sender)); writerWorker.logAdd("[system]", "catch/handled CTCP PING from", sender);
//System.out.println(":"+simplifyNick(sender)+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" "+message); //System.out.println(":"+sender+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" "+message);
} }
else if (message.equals("\u0001CLIENTINFO\u0001")){ else if (message.equals("\u0001CLIENTINFO\u0001")){
StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :\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", simplifyNick(sender)); writerWorker.logAdd("[system]", "catch/handled CTCP CLIENTINFO from", sender);
//System.out.println(":"+simplifyNick(sender)+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" \u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO\u0001"); //System.out.println(":"+sender+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" \u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO\u0001");
} }
else if (message.equals("\u0001TIME\u0001")){ else if (message.equals("\u0001TIME\u0001")){
StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :\u0001TIME "+ ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\u0001"); StreamProvider.writeToStream(serverName,"NOTICE "+sender+" :\u0001TIME "+ ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\u0001");
writerWorker.logAdd("[system]", "catch/handled CTCP TIME from", simplifyNick(sender)); writerWorker.logAdd("[system]", "catch/handled CTCP TIME from", sender);
//System.out.println(":"+simplifyNick(sender)+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" \u0001TIME "+ ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\u0001"); //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 CTCP request \""+message+"\" from ", simplifyNick(sender));
} }
else
writerWorker.logAdd("[system]", "catch unknown CTCP request \""+message+"\" from ", sender);
}
private String simplifyNick(String nick){ return nick.replaceAll("!.*$",""); } private String simplifyNick(String nick){ return nick.replaceAll("!.*$",""); }
@ -197,12 +201,12 @@ public class SystemConsumer implements Runnable{
} }
} }
else 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; break;
case "NICK": case "NICK":
if (sender.startsWith(nick+"!")) { if (sender.startsWith(nick+"!")) {
nick = message.trim(); 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; break;
case "JOIN": case "JOIN":
@ -210,10 +214,11 @@ public class SystemConsumer implements Runnable{
proxyAList.put(message, new ArrayList<>()); // Add new channel name to proxy watch-list 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 proxyAList.get(message).add(eventNum+" "+sender+" "+message); // Add message to array linked
this.proxyRequired = true; // Ask for proxy validators this.proxyRequired = true; // Ask for proxy validators
writerWorker.logAdd("[system]", "joined to channel ", "message");
} }
break; break;
default: default:
writerWorker.logAdd("[system]", "catch: "+eventNum+" from: "+sender+" :",message); writerWorker.logAdd("[system]", "catch: "+eventNum+" from: "+sender+" :",message); // TODO: QUIT comes here. Do something.
break; break;
} }
} }

View file

@ -1,39 +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", "SQLiteDriver", 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");
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("PART", "de_su!loper@desktop.lan", "#chan1");
fw2.logAdd("JOIN", "de_su!loper@desktop.lan", "message2");
fw2.logAdd("PART", "de_su!loper@desktop.lan", "#chan2");
fw3.logAdd("JOIN", "de_su!loper@desktop.lan", "message3");
fw3.logAdd("PART", "de_su!loper@desktop.lan", "#chan3");
fw1.close();
fw2.close();
fw3.close();
}
}
}

View file

@ -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/"}, "/tmp/appLogs/"))
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();
}
}
}

View file

@ -0,0 +1,74 @@
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"},
"/tmp/appLogs/"))
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();
}
}
}

View file

@ -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"}, "/tmp/appLogs/"))
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();
}
}
}

View file

@ -3,7 +3,7 @@ package Temporary;
import InnaIrcBot.ReconnectControl; import InnaIrcBot.ReconnectControl;
public class ReconnectControlTest { public class ReconnectControlTest {
public static void main(String args[]){ public static void main(String[] args){
ReconnectControl.register("testing"); ReconnectControl.register("testing");
ReconnectControl.register("testing1"); ReconnectControl.register("testing1");
ReconnectControl.update("testing1", false); ReconnectControl.update("testing1", false);

View file

@ -19,6 +19,7 @@ public class StorageFileTest {
"", "",
new String[]{null}, new String[]{null},
"", "",
"",
"" ""
); );