Start rewriting everything
This commit is contained in:
parent
9fcb953ba5
commit
3cf0e2fa0f
42 changed files with 1507 additions and 1377 deletions
4
Jenkinsfile
vendored
4
Jenkinsfile
vendored
|
@ -9,12 +9,12 @@ pipeline {
|
|||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'mvn -B -DskipTests clean package'
|
||||
sh 'mvn package'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
echo 'Skip testing...'
|
||||
sh 'mvn test'
|
||||
}
|
||||
}
|
||||
stage('Deploy') {
|
||||
|
|
31
README.md
31
README.md
|
@ -2,12 +2,22 @@
|
|||
|
||||
Another one IRC bot in deep-deep beta.
|
||||
|
||||
## License
|
||||
Source code spreads under the GNU General Public License v3 or higher. Please see LICENSE file.
|
||||
|
||||
####Used libraries:
|
||||
* Apache commons CLI: https://commons.apache.org/proper/commons-cli/
|
||||
* 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/
|
||||
* JUnit 5: https://junit.org/junit5/
|
||||
|
||||
## Usage
|
||||
` -c, --configuration <name.config> [<name1.config> ...] Read Config`
|
||||
|
||||
` -g, --generate [name.config] Generate Config`
|
||||
|
||||
` -v, --version Get application version`
|
||||
```
|
||||
-c, --configuration <name.config> [<name1.config> ...] Read Config
|
||||
-g, --generate [name.config] Generate Config
|
||||
-v, --version Get application version
|
||||
```
|
||||
#### Configuration settings
|
||||
"userNickAuthStyle": "rusnet" or "freenode"
|
||||
* rusnet - send '/nickserv IDENTIFY mySecretPass'
|
||||
|
@ -18,16 +28,7 @@ Another one IRC bot in deep-deep beta.
|
|||
* 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.
|
||||
|
||||
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:
|
||||
### TODO:
|
||||
- [ ] Documentation
|
||||
- [ ] Code refactoring
|
||||
- [ ] QA: good regression testing
|
||||
|
|
85
pom.xml
85
pom.xml
|
@ -4,13 +4,14 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>loper</groupId>
|
||||
<artifactId>InnaIrcBot</artifactId>
|
||||
<version>0.7-SNAPSHOT</version>
|
||||
<version>0.8-SNAPSHOT</version>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
<name>InnaIrcBot</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
|
@ -30,31 +31,78 @@
|
|||
<version>3.9.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.4</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.5.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.5.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>5.5.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build><plugins>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- ====================================================== -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<excludes>
|
||||
<exclude>
|
||||
**/Temporary/*
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
<!-- ====================================================== -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<excludes>
|
||||
<exclude>
|
||||
**/Temporary/*
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-jar</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>
|
||||
InnaIrcBot.BotStart
|
||||
InnaIrcBot.Main
|
||||
</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
|
@ -72,6 +120,7 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins></build>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -1,3 +0,0 @@
|
|||
Manifest-Version: 1.0
|
||||
Main-Class: InnaIrcBot.BotStart
|
||||
|
|
@ -1,38 +1,97 @@
|
|||
/**
|
||||
* InnaIrcBot
|
||||
* @author Dmitry Isaenko
|
||||
* Russia, 2018-2019.
|
||||
* */
|
||||
package InnaIrcBot;
|
||||
|
||||
import InnaIrcBot.Config.StorageReader;
|
||||
import InnaIrcBot.config.ConfigurationFileGenerator;
|
||||
import org.apache.commons.cli.*;
|
||||
|
||||
public class BotStart {
|
||||
//TODO: flood control
|
||||
//TODO: setDaemon(true)
|
||||
//TODO: multiple connections to one server not allowed
|
||||
public BotStart(String[] args){
|
||||
|
||||
public static void main(String[] args){
|
||||
if (args.length != 0) {
|
||||
if (args.length >= 2) {
|
||||
if (args[0].equals("--configuration") || args[0].equals("-c")) {
|
||||
new Connections(args);
|
||||
} else if (args[0].equals("--generate") || args[0].equals("-g")) {
|
||||
StorageReader.generateDefaultConfig(args[1]);
|
||||
}
|
||||
final Options cliOptions = createCliOptions();
|
||||
CommandLineParser cliParser = new DefaultParser();
|
||||
|
||||
try{
|
||||
CommandLine cli = cliParser.parse(cliOptions, args);
|
||||
if (cli.hasOption('v') || cli.hasOption("version")){
|
||||
handleVersion();
|
||||
return;
|
||||
}
|
||||
else if (args[0].equals("--generate") || args[0].equals("-g")){
|
||||
StorageReader.generateDefaultConfig(null);
|
||||
if (cli.hasOption("c") || cli.hasOption("configuration")){
|
||||
final String[] arguments = cli.getOptionValues("configuration");
|
||||
for (String a: arguments)
|
||||
ConnectionsBuilder.buildConnections(arguments);
|
||||
return;
|
||||
}
|
||||
else if (args[0].equals("--version") || args[0].equals("-v")) {
|
||||
System.out.println(GlobalData.getAppVersion());
|
||||
if (cli.hasOption("g") || cli.hasOption("generate")){
|
||||
final String[] arguments = cli.getOptionValues("generate");
|
||||
handleGenerate(arguments);
|
||||
return;
|
||||
}
|
||||
|
||||
handleHelp(cliOptions);
|
||||
}
|
||||
else {
|
||||
System.out.println("Usage:\n"
|
||||
+" \t-c, --configuration <name.config> [<name1.config> ...]\tRead Config\n"
|
||||
+"\t-g, --generate\t[name.config]\t\t\t\tGenerate Config\n"
|
||||
+"\t-v, --version\t\t\t\t\t\tGet application version");
|
||||
catch (ParseException pe){
|
||||
handleHelp(cliOptions);
|
||||
}
|
||||
catch (Exception e){
|
||||
System.out.println("Error: ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
private Options createCliOptions(){
|
||||
final Options options = new Options();
|
||||
|
||||
final Option helpOption = Option.builder("h")
|
||||
.longOpt("help")
|
||||
.desc("Show this help")
|
||||
.hasArg(false)
|
||||
.build();
|
||||
|
||||
final Option versionOption = Option.builder("v")
|
||||
.longOpt("version")
|
||||
.desc("Show application version")
|
||||
.hasArg(false)
|
||||
.build();
|
||||
|
||||
final Option configurationOption = Option.builder("c")
|
||||
.longOpt("configuration")
|
||||
.desc("Start with configuration")
|
||||
.hasArg(true)
|
||||
.build();
|
||||
|
||||
final Option generateOption = Option.builder("g")
|
||||
.longOpt("generate")
|
||||
.desc("Create configuration template")
|
||||
.hasArg(true)
|
||||
.numberOfArgs(1)
|
||||
.build();
|
||||
|
||||
final OptionGroup group = new OptionGroup();
|
||||
group.addOption(helpOption);
|
||||
group.addOption(versionOption);
|
||||
group.addOption(configurationOption);
|
||||
group.addOption(generateOption);
|
||||
|
||||
options.addOptionGroup(group);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private void handleVersion(){
|
||||
System.out.println(GlobalData.getAppVersion());
|
||||
}
|
||||
|
||||
private void handleHelp(Options cliOptions){
|
||||
new HelpFormatter().printHelp(
|
||||
120,
|
||||
"InnaIrcBot.jar [OPTION]... [FILE]...",
|
||||
"options:",
|
||||
cliOptions,
|
||||
"\n");
|
||||
}
|
||||
private void handleGenerate(String[] arguments){
|
||||
if (arguments.length > 0)
|
||||
ConfigurationFileGenerator.generate(arguments[0]);
|
||||
else
|
||||
ConfigurationFileGenerator.generate(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,19 +12,12 @@ public class CTCPHelper {
|
|||
private static final CTCPHelper instance = new CTCPHelper();
|
||||
public static CTCPHelper getInstance(){ return instance; }
|
||||
|
||||
private final HashMap<String, List<CTCPRequest>> waitersQueue = new HashMap<>();
|
||||
private CTCPHelper(){}
|
||||
|
||||
private HashMap<String, List<CtcpRequest>> waitersQueue = new HashMap<>();
|
||||
|
||||
void registerRequest(String requesterServer, String requesterChanelOrUser, String ctcpType, String targetObject, String notFoundMessage){
|
||||
/*
|
||||
System.out.println("Server:|"+requesterServer+"|");
|
||||
System.out.println("Chanel:|"+requesterChanelOrUser+"|");
|
||||
System.out.println("Type :|"+ctcpType+"|");
|
||||
System.out.println("Regexp:|"+targetObject+"|");
|
||||
System.out.println("NF_mes:|"+notFoundMessage+"|\n"); // could be empty
|
||||
*/
|
||||
if (!waitersQueue.containsKey(requesterServer)){ // TODO: meeeeeeeehh.. looks bad
|
||||
waitersQueue.put(requesterServer, new ArrayList<>());
|
||||
void registerRequest(String server, String requesterChanelOrUser, String ctcpType, String target, String notFoundMessage){
|
||||
if (!waitersQueue.containsKey(server)){ // TODO: meeeeeeeehh.. looks bad
|
||||
waitersQueue.put(server, new ArrayList<>());
|
||||
}
|
||||
|
||||
switch (ctcpType){
|
||||
|
@ -34,107 +27,67 @@ public class CTCPHelper {
|
|||
case "SOURCE":
|
||||
case "TIME":
|
||||
case "USERINFO":
|
||||
waitersQueue.get(requesterServer).add(new CtcpRequest(requesterChanelOrUser, targetObject, notFoundMessage, ctcpType));
|
||||
StreamProvider.writeToStream(requesterServer, "PRIVMSG "+targetObject+" :\u0001"+ctcpType+"\u0001");
|
||||
waitersQueue.get(server).add(new CTCPRequest(requesterChanelOrUser, target, notFoundMessage, ctcpType));
|
||||
StreamProvider.writeToStream(server, "PRIVMSG "+target+" :\u0001"+ctcpType+"\u0001");
|
||||
break;
|
||||
case "PING": // TODO
|
||||
waitersQueue.get(requesterServer).add(new CtcpRequest(requesterChanelOrUser, targetObject, notFoundMessage, ctcpType));
|
||||
StreamProvider.writeToStream(requesterServer, "PRIVMSG "+targetObject+" :\u0001PING inna\u0001");
|
||||
waitersQueue.get(server).add(new CTCPRequest(requesterChanelOrUser, target, notFoundMessage, ctcpType));
|
||||
StreamProvider.writeToStream(server, "PRIVMSG "+target+" :\u0001PING inna\u0001");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void handleCtcpReply(String serverReplied, String whoReplied, String whatReplied){
|
||||
//System.out.println("Reply serv:|"+serverReplied+"|\nwho:|"+whoReplied+"|\nwhat:|"+whatReplied+"|");
|
||||
LocalDateTime currentTime = LocalDateTime.now();
|
||||
if (waitersQueue.containsKey(serverReplied)){
|
||||
ListIterator<CtcpRequest> iterator = waitersQueue.get(serverReplied).listIterator();
|
||||
CtcpRequest current;
|
||||
String chanelOrUser;
|
||||
while (iterator.hasNext()){
|
||||
current = iterator.next();
|
||||
if (current.isValid(currentTime)){
|
||||
chanelOrUser = current.getRequesterChanelOrUser(whoReplied);
|
||||
if ( chanelOrUser != null && current.getType().equals(whatReplied.replaceAll("\\s.*$", ""))) {
|
||||
if (whatReplied.equals("PING inna"))
|
||||
StreamProvider.writeToStream(serverReplied, "PRIVMSG " + chanelOrUser + " :" + whoReplied + ": " + Duration.between(current.getCreationTime(), currentTime).toMillis()+"ms");
|
||||
else
|
||||
StreamProvider.writeToStream(serverReplied, "PRIVMSG " + chanelOrUser + " :" + whoReplied + ": " + whatReplied);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
else{
|
||||
//System.out.println("Drop outdated user");
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
if (! waitersQueue.containsKey(serverReplied))
|
||||
return;
|
||||
|
||||
ListIterator<CTCPRequest> iterator = waitersQueue.get(serverReplied).listIterator();
|
||||
|
||||
while (iterator.hasNext()){
|
||||
CTCPRequest current = iterator.next();
|
||||
if (current.isValid(currentTime)){
|
||||
String channelOrUser = current.getRequesterChanelOrUser(whoReplied);
|
||||
|
||||
if (channelOrUser == null || ! current.getType().equals(whatReplied.replaceAll("\\s.*$", "")))
|
||||
continue;
|
||||
|
||||
if (whatReplied.equals("PING inna"))
|
||||
StreamProvider.writeToStream(serverReplied, "PRIVMSG " + channelOrUser + " :" + whoReplied + ": " +
|
||||
Duration.between(current.getCreationTime(), currentTime).toMillis()+"ms");
|
||||
else
|
||||
StreamProvider.writeToStream(serverReplied, "PRIVMSG " + channelOrUser + " :" + whoReplied + ": " + whatReplied);
|
||||
}
|
||||
iterator.remove();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void handleErrorReply(String serverReplied, String whoNotFound){
|
||||
//System.out.println("Reply serv:|"+serverReplied+"|\nwho:|"+whoNotFound+"|\n");
|
||||
LocalDateTime currentTime = LocalDateTime.now();
|
||||
if (waitersQueue.containsKey(serverReplied)){
|
||||
ListIterator<CtcpRequest> iterator = waitersQueue.get(serverReplied).listIterator();
|
||||
CtcpRequest current;
|
||||
String chanelOrUser;
|
||||
String notFoundMessage;
|
||||
while (iterator.hasNext()){
|
||||
current = iterator.next();
|
||||
if (current.isValid(currentTime)){
|
||||
chanelOrUser = current.getRequesterChanelOrUser(whoNotFound);
|
||||
if ( chanelOrUser != null) {
|
||||
notFoundMessage = current.getNotFoundMessage(whoNotFound);
|
||||
if ( notFoundMessage != null) {
|
||||
System.out.println(serverReplied + " PRIVMSG " + chanelOrUser + " :" + notFoundMessage + whoNotFound);
|
||||
StreamProvider.writeToStream(serverReplied, "PRIVMSG " + chanelOrUser + " :" + notFoundMessage + whoNotFound);
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
else{
|
||||
//System.out.println("Drop outdated user: 401");
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
if (! waitersQueue.containsKey(serverReplied))
|
||||
return;
|
||||
|
||||
ListIterator<CTCPRequest> iterator = waitersQueue.get(serverReplied).listIterator();
|
||||
|
||||
while (iterator.hasNext()){
|
||||
CTCPRequest current = iterator.next();
|
||||
if (! current.isValid(currentTime))
|
||||
iterator.remove();
|
||||
String channelOrUser = current.getRequesterChanelOrUser(whoNotFound);
|
||||
|
||||
if (channelOrUser == null)
|
||||
continue;
|
||||
|
||||
String notFoundMessage = current.getNotFoundMessage(whoNotFound);
|
||||
|
||||
if (notFoundMessage == null)
|
||||
continue;
|
||||
|
||||
System.out.println(serverReplied + " PRIVMSG " + channelOrUser + " :" + notFoundMessage + whoNotFound);
|
||||
StreamProvider.writeToStream(serverReplied, "PRIVMSG " + channelOrUser + " :" + notFoundMessage + whoNotFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CtcpRequest {
|
||||
private String requesterChanelOrUser;
|
||||
private String userResponding;
|
||||
private LocalDateTime initiatedTime;
|
||||
private String notFoundMessage;
|
||||
private String CTCPtype;
|
||||
CtcpRequest (String whoIsAsking, String userResponding, String notFoundMessage, String CTCPType){
|
||||
this.initiatedTime = LocalDateTime.now();
|
||||
this.requesterChanelOrUser = whoIsAsking;
|
||||
this.userResponding = userResponding;
|
||||
this.notFoundMessage = notFoundMessage;
|
||||
this.CTCPtype = CTCPType;
|
||||
}
|
||||
String getRequesterChanelOrUser(String userResponds){ // return channel name
|
||||
if (userResponding.equals(userResponds))
|
||||
return requesterChanelOrUser;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
boolean isValid(LocalDateTime currentTime){
|
||||
return currentTime.isBefore(initiatedTime.plusSeconds(5));
|
||||
}
|
||||
|
||||
String getType(){ return CTCPtype; }
|
||||
|
||||
LocalDateTime getCreationTime(){ return initiatedTime; }
|
||||
|
||||
String getNotFoundMessage(String userResponds){
|
||||
if (this.userResponding.equals(userResponds))
|
||||
if (notFoundMessage.isEmpty())
|
||||
return null;
|
||||
else
|
||||
return notFoundMessage;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
39
src/main/java/InnaIrcBot/Commanders/CTCPRequest.java
Normal file
39
src/main/java/InnaIrcBot/Commanders/CTCPRequest.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
package InnaIrcBot.Commanders;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
class CTCPRequest {
|
||||
private final String requesterChanelOrUser;
|
||||
private final String userResponding;
|
||||
private final LocalDateTime initiatedTime;
|
||||
private final String notFoundMessage;
|
||||
private final String CTCPtype;
|
||||
|
||||
CTCPRequest(String whoIsAsking, String userResponding, String notFoundMessage, String CTCPType){
|
||||
this.initiatedTime = LocalDateTime.now();
|
||||
this.requesterChanelOrUser = whoIsAsking;
|
||||
this.userResponding = userResponding;
|
||||
this.notFoundMessage = notFoundMessage;
|
||||
this.CTCPtype = CTCPType;
|
||||
}
|
||||
|
||||
String getRequesterChanelOrUser(String userResponds){ // return channel name
|
||||
if (userResponding.equals(userResponds))
|
||||
return requesterChanelOrUser;
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean isValid(LocalDateTime currentTime){
|
||||
return currentTime.isBefore(initiatedTime.plusSeconds(5));
|
||||
}
|
||||
|
||||
String getType(){ return CTCPtype; }
|
||||
|
||||
LocalDateTime getCreationTime(){ return initiatedTime; }
|
||||
|
||||
String getNotFoundMessage(String userResponds){
|
||||
if (userResponding.equals(userResponds) && ! notFoundMessage.isEmpty())
|
||||
return notFoundMessage;
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -8,17 +8,18 @@ import java.time.format.DateTimeFormatter;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.regex.Pattern;
|
||||
//TODO: FLOOD, JOIN FLOOD
|
||||
// TODO: @ configuration level: if in result we have empty string, no need to pass it to server
|
||||
public class ChanelCommander implements Runnable {
|
||||
private BufferedReader reader;
|
||||
private String server;
|
||||
private String chanel;
|
||||
private final BlockingQueue<String> streamQueue;
|
||||
private final String server;
|
||||
private final String channel;
|
||||
//TODO: add timers
|
||||
private HashMap<String, String[]> joinMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw
|
||||
private HashMap<String, String[]> msgMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw
|
||||
private HashMap<String, String[]> nickMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw
|
||||
private final HashMap<String, String[]> joinMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw
|
||||
private final HashMap<String, String[]> msgMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw
|
||||
private final HashMap<String, String[]> nickMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw
|
||||
|
||||
private boolean joinFloodTrackNeed = false;
|
||||
private JoinFloodHandler jfh;
|
||||
|
@ -26,10 +27,10 @@ public class ChanelCommander implements Runnable {
|
|||
private boolean joinCloneTrackNeed = false; // todo:fix
|
||||
private JoinCloneHandler jch;
|
||||
|
||||
public ChanelCommander(BufferedReader streamReader, String serverName, String chan, String configFilePath){
|
||||
this.reader = streamReader;
|
||||
public ChanelCommander(BlockingQueue<String> stream, String serverName, String channel, String configFilePath){
|
||||
this.streamQueue = stream;
|
||||
this.server = serverName;
|
||||
this.chanel = chan;
|
||||
this.channel = channel;
|
||||
|
||||
this.joinMap = new HashMap<>();
|
||||
this.msgMap = new HashMap<>();
|
||||
|
@ -39,13 +40,13 @@ public class ChanelCommander implements Runnable {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Thread for ChanelCommander started"); // TODO:REMOVE DEBUG
|
||||
String data;
|
||||
String[] dataStrings;
|
||||
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] ChanelCommander thread "
|
||||
+server+":"+this.channel +" started");// TODO:REMOVE DEBUG
|
||||
try {
|
||||
while ((data = reader.readLine()) != null) {
|
||||
dataStrings = data.split(" ",3);
|
||||
//event initiatorArg messageArg
|
||||
while (true) {
|
||||
String data = streamQueue.take();
|
||||
String[] dataStrings = data.split(" ",3);
|
||||
|
||||
switch (dataStrings[0]) {
|
||||
case "NICK":
|
||||
nickCame(dataStrings[2]+dataStrings[1].replaceAll("^.+?!","!"));
|
||||
|
@ -75,8 +76,9 @@ public class ChanelCommander implements Runnable {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} catch (java.io.IOException e){
|
||||
System.out.println("Internal issue: thread ChanelCommander->run() caused I/O exception:\n\t"+e); // TODO: reconnect
|
||||
}
|
||||
catch (InterruptedException ie){
|
||||
System.out.println("Internal issue: thread ChanelCommander->run() interrupted.\n\t"); // TODO: reconnect
|
||||
}
|
||||
System.out.println("Thread for ChanelCommander ended"); // TODO:REMOVE DEBUG
|
||||
}
|
||||
|
@ -175,7 +177,7 @@ public class ChanelCommander implements Runnable {
|
|||
String objectToCtcp = arg1.trim().replaceAll(objectRegexp, ""); // note: trim() ?
|
||||
if (!objectToCtcp.isEmpty()){
|
||||
if (CTCPType.startsWith("\\c"))
|
||||
CTCPHelper.getInstance().registerRequest(server, chanel, CTCPType.substring(2).toUpperCase(), objectToCtcp, whatToSendStringBuilder.toString());
|
||||
CTCPHelper.getInstance().registerRequest(server, channel, CTCPType.substring(2).toUpperCase(), objectToCtcp, whatToSendStringBuilder.toString());
|
||||
else
|
||||
CTCPHelper.getInstance().registerRequest(server, simplifyNick(arg2), CTCPType.substring(2).toUpperCase(), objectToCtcp, whatToSendStringBuilder.toString());
|
||||
}
|
||||
|
@ -201,40 +203,40 @@ public class ChanelCommander implements Runnable {
|
|||
executiveStr.append(" :");
|
||||
}
|
||||
else {
|
||||
executiveStr.append(chanel);
|
||||
executiveStr.append(channel);
|
||||
executiveStr.append(" :");
|
||||
executiveStr.append(simplifyNick(who));
|
||||
executiveStr.append(": ");
|
||||
}
|
||||
|
||||
for (int i = 0; i < messages.length; i++){
|
||||
if ( ! messages[i].startsWith("\\"))
|
||||
executiveStr.append(messages[i]);
|
||||
else if (messages[i].equals("\\time")) // TODO: remove this shit
|
||||
for (String message : messages) {
|
||||
if (!message.startsWith("\\"))
|
||||
executiveStr.append(message);
|
||||
else if (message.equals("\\time")) // TODO: remove this shit
|
||||
executiveStr.append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
}
|
||||
//System.out.println(executiveStr.toString()); //TODO: debug
|
||||
StreamProvider.writeToStream(server, executiveStr.toString());
|
||||
}
|
||||
private void banAction(String whom){
|
||||
StreamProvider.writeToStream(server, "MODE "+chanel+" +b "+simplifyNick(whom)+"*!*@*");
|
||||
StreamProvider.writeToStream(server, "MODE "+chanel+" +b "+"*!*@"+whom.replaceAll("^.+@",""));
|
||||
StreamProvider.writeToStream(server, "MODE "+ channel +" +b "+simplifyNick(whom)+"*!*@*");
|
||||
StreamProvider.writeToStream(server, "MODE "+ channel +" +b "+"*!*@"+whom.replaceAll("^.+@",""));
|
||||
}
|
||||
private void voiceAction(String whom){
|
||||
StreamProvider.writeToStream(server, "MODE "+chanel+" +v "+simplifyNick(whom));
|
||||
StreamProvider.writeToStream(server, "MODE "+ channel +" +v "+simplifyNick(whom));
|
||||
}
|
||||
private void kickAction(String[] messages, String whom){
|
||||
StringBuilder executiveStr = new StringBuilder();
|
||||
executiveStr.append("KICK ");
|
||||
executiveStr.append(chanel);
|
||||
executiveStr.append(channel);
|
||||
executiveStr.append(" ");
|
||||
executiveStr.append(simplifyNick(whom));
|
||||
executiveStr.append(" :");
|
||||
|
||||
for (int i = 0; i < messages.length; i++){
|
||||
if ( ! messages[i].startsWith("\\"))
|
||||
executiveStr.append(messages[i]);
|
||||
else if (messages[i].equals("\\time"))
|
||||
for (String message : messages) {
|
||||
if (!message.startsWith("\\"))
|
||||
executiveStr.append(message);
|
||||
else if (message.equals("\\time"))
|
||||
executiveStr.append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
}
|
||||
StreamProvider.writeToStream(server, executiveStr.toString());
|
||||
|
@ -256,12 +258,13 @@ public class ChanelCommander implements Runnable {
|
|||
break;
|
||||
case "joinfloodcontrol":
|
||||
if (!directive[1].isEmpty() && !directive[2].isEmpty() && Pattern.matches("^[0-9]+?$", directive[1].trim()) && Pattern.matches("^[0-9]+?$", directive[2].trim())) {
|
||||
int events = Integer.valueOf(directive[1].trim());
|
||||
int timeFrame = Integer.valueOf(directive[2].trim());
|
||||
int events = Integer.parseInt(directive[1].trim());
|
||||
int timeFrame = Integer.parseInt(directive[2].trim());
|
||||
if (events > 0 && timeFrame > 0) {
|
||||
jfh = new JoinFloodHandler(events, timeFrame, server, chanel);
|
||||
jfh = new JoinFloodHandler(events, timeFrame, server, channel);
|
||||
joinFloodTrackNeed = true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
System.out.println("Internal issue: thread ChanelCommander->parse(): 'Number of events' and/or 'Time Frame in seconds' should be greater than 0");
|
||||
}
|
||||
}
|
||||
|
@ -270,9 +273,9 @@ public class ChanelCommander implements Runnable {
|
|||
break;
|
||||
case "joinclonecontrol":
|
||||
if (!directive[1].isEmpty() && !directive[2].isEmpty() && Pattern.matches("^[0-9]+?$", directive[1].trim())) {
|
||||
int events = Integer.valueOf(directive[1].trim());
|
||||
int events = Integer.parseInt(directive[1].trim());
|
||||
if (events > 0){
|
||||
jch = new JoinCloneHandler(directive[2], events, server, chanel); // TODO: REMOVE
|
||||
jch = new JoinCloneHandler(directive[2], events, server, channel); // TODO: REMOVE
|
||||
joinCloneTrackNeed = true;
|
||||
}
|
||||
else {
|
||||
|
@ -289,7 +292,9 @@ public class ChanelCommander implements Runnable {
|
|||
private void readConfing(String confFilesPath){
|
||||
if (!confFilesPath.endsWith(File.separator))
|
||||
confFilesPath += File.separator;
|
||||
File file = new File(confFilesPath+server+chanel+".csv"); // TODO: add/search for filename
|
||||
|
||||
File file = new File(confFilesPath+server+ channel +".csv"); // TODO: add/search for filename
|
||||
|
||||
if (!file.exists())
|
||||
return;
|
||||
try {
|
||||
|
@ -298,10 +303,9 @@ public class ChanelCommander implements Runnable {
|
|||
while ((line = br.readLine()) != null) {
|
||||
parse(line.split("\t"));
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("Internal issue: thread ChanelCommander->readConfig() can't find file:\t\n"+e);
|
||||
} catch (IOException e){
|
||||
System.out.println("Internal issue: thread ChanelCommander->readConfig() I/O exception:\t\n"+e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("Internal issue: thread ChanelCommander->readConfig():\t\n"+e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ public class JoinCloneHandler {
|
|||
prevUserNick = "";
|
||||
lastCame = LocalDateTime.now().minusDays(1L);
|
||||
}
|
||||
|
||||
/*
|
||||
public void track(String userNick){
|
||||
if (userNick.matches(pattern)){
|
||||
if (lastCame.isAfter(LocalDateTime.now().minusSeconds(timeFrameInSeconds)) && !prevUserNick.equals(userNick)){
|
||||
|
@ -37,8 +37,41 @@ public class JoinCloneHandler {
|
|||
lastCame = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
*/
|
||||
// RUSNET
|
||||
public void track(String userNick){
|
||||
if (userNick.matches(pattern)){
|
||||
if (lastCame.isAfter(LocalDateTime.now().minusSeconds(timeFrameInSeconds)) && !prevUserNick.equals(userNick)){
|
||||
if (getNickOnly(userNick).replaceAll("[0-9].*", "").length() > 2){
|
||||
StreamProvider.writeToStream(server,
|
||||
"MODE "+chanel+" +b "+userNick.replaceAll("[0-9].*", "*!*@*")+"\n"+
|
||||
"MODE "+chanel+" +b *!*@"+getIdentHost(userNick)+"*\n"+
|
||||
"MODE "+chanel+" +b "+prevUserNick.replaceAll("[0-9].*", "*!*@*")+"\n"+
|
||||
"MODE "+chanel+" +b *!*@"+getIdentHost(prevUserNick)+"*\n"+
|
||||
"KICK "+chanel+" "+getNickOnly(userNick)+" :clone\n"+
|
||||
"KICK "+chanel+" "+getNickOnly(prevUserNick)+" :clone"
|
||||
);
|
||||
}
|
||||
else {
|
||||
StreamProvider.writeToStream(server,
|
||||
"MODE "+chanel+" +b *!*@"+getIdentHost(userNick)+"*\n"+
|
||||
"MODE "+chanel+" +b *!*@"+getIdentHost(prevUserNick)+"*\n"+
|
||||
"KICK "+chanel+" "+getNickOnly(userNick)+" :clone\n"+
|
||||
"KICK "+chanel+" "+getNickOnly(prevUserNick)+" :clone"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
prevUserNick = userNick;
|
||||
lastCame = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
private String getIdentHost(String fullNick){
|
||||
return fullNick.replaceAll("^.*@","@");
|
||||
String id = fullNick.replaceAll("^.*@","");
|
||||
if (id.contains(":"))
|
||||
return id.replaceAll("^([A-Fa-f0-9]{1,4}:[A-Fa-f0-9]{1,4}:)(.+)$", "$1")+"*";
|
||||
else
|
||||
return id;
|
||||
}
|
||||
private String getNickOnly(String fullNick){
|
||||
return fullNick.replaceAll("!.*$","");
|
||||
|
|
|
@ -3,58 +3,68 @@ package InnaIrcBot.Commanders;
|
|||
import InnaIrcBot.ProvidersConsumers.StreamProvider;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
//TODO: implement method to
|
||||
public class JoinFloodHandler {
|
||||
private int eventBufferSize; // How many events should happens before we start validation
|
||||
private int timeFrameInSeconds; // For which period critical amount of events should happens
|
||||
private String server;
|
||||
private String chanel;
|
||||
private HashMap<String, LprFIFOQueue> usersOnChanel;
|
||||
import java.util.*;
|
||||
|
||||
public JoinFloodHandler(int events, int timeFrameInSeconds, String serverName, String chanelName){
|
||||
this.eventBufferSize = events;
|
||||
public class JoinFloodHandler {
|
||||
private final int joinMaxNumber; // How many events should happens before we start validation
|
||||
private final int timeFrameInSeconds; // For which period critical amount of events should happens
|
||||
private final String server;
|
||||
private final String channel;
|
||||
protected final HashMap<String, LinkedList<LocalDateTime>> users;
|
||||
|
||||
public JoinFloodHandler(int joinMaxNumber, int timeFrameInSeconds, String serverName, String channelName){
|
||||
this.joinMaxNumber = joinMaxNumber;
|
||||
this.timeFrameInSeconds = timeFrameInSeconds;
|
||||
this.server = serverName;
|
||||
this.chanel = chanelName;
|
||||
this.usersOnChanel = new HashMap<>();
|
||||
this.channel = channelName;
|
||||
this.users = new HashMap<>();
|
||||
}
|
||||
|
||||
public void track(String userNick){
|
||||
if(usersOnChanel.containsKey(userNick)){
|
||||
LocalDateTime timeOfFirstEvent = usersOnChanel.get(userNick).addLastGetFirst();
|
||||
if (timeOfFirstEvent.isAfter(LocalDateTime.now().minusSeconds(timeFrameInSeconds))) { // If first event in the queue happened after 'timeFrameSeconds ago from now'
|
||||
StreamProvider.writeToStream(server, "PRIVMSG "+chanel+" :"+userNick+": join flood ("+eventBufferSize+" connections in "+timeFrameInSeconds+" seconds).\n"+
|
||||
"MODE "+chanel+" +b "+userNick+"!*@*"); // Shut joins-liker down. By nick TODO: consider other ban methods
|
||||
usersOnChanel.remove(userNick); // Delete viewing history (in case op/hop decided to unban)
|
||||
}
|
||||
public void track(String userNickname){
|
||||
if (isNewcomer(userNickname)) {
|
||||
registerNewUser(userNickname);
|
||||
return;
|
||||
}
|
||||
|
||||
if(isJoinFlooder(userNickname)){
|
||||
kickBanUser(userNickname);
|
||||
users.remove(userNickname);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNewcomer(String user){
|
||||
return ! users.containsKey(user);
|
||||
}
|
||||
|
||||
private void registerNewUser(String user){
|
||||
users.put(user, new LinkedList<>());
|
||||
users.get(user).addFirst(LocalDateTime.now());
|
||||
}
|
||||
|
||||
private boolean isJoinFlooder(String user){
|
||||
final LocalDateTime firstJoinTime = getFirstJoinTimeAndUpdate(user);
|
||||
return firstJoinTime.isAfter(LocalDateTime.now().minusSeconds(timeFrameInSeconds));
|
||||
}
|
||||
|
||||
private LocalDateTime getFirstJoinTimeAndUpdate(String user){
|
||||
LinkedList<LocalDateTime> userJoinHistory = users.get(user);
|
||||
LocalDateTime fistJoinTime;
|
||||
|
||||
userJoinHistory.addLast(LocalDateTime.now());
|
||||
|
||||
if (userJoinHistory.size() > joinMaxNumber){
|
||||
fistJoinTime = userJoinHistory.getFirst();
|
||||
userJoinHistory.removeFirst();
|
||||
}
|
||||
else {
|
||||
usersOnChanel.put(userNick, new LprFIFOQueue(eventBufferSize)); // Create buffer for tracking new user joined
|
||||
usersOnChanel.get(userNick).addLastGetFirst(); // Write his/her first join time
|
||||
fistJoinTime = LocalDateTime.MIN;
|
||||
}
|
||||
|
||||
return fistJoinTime;
|
||||
}
|
||||
}
|
||||
|
||||
class LprFIFOQueue {
|
||||
private int size;
|
||||
private ArrayList<LocalDateTime> dateTimes;// todo stack or deque
|
||||
|
||||
LprFIFOQueue(int size){
|
||||
this.size = size;
|
||||
this.dateTimes = new ArrayList<>();
|
||||
}
|
||||
|
||||
LocalDateTime addLastGetFirst(){ // FIFO-like
|
||||
// set
|
||||
if (dateTimes.size() >= size)
|
||||
dateTimes.remove(0);
|
||||
dateTimes.add(LocalDateTime.now()); // add current time
|
||||
// get
|
||||
if (dateTimes.size() < size)
|
||||
return LocalDateTime.MIN; // todo: check if null is better
|
||||
else
|
||||
return dateTimes.get(0);
|
||||
private void kickBanUser(String user){
|
||||
StreamProvider.writeToStream(server,
|
||||
"PRIVMSG "+ channel +" :"+user+": join flood ("+ joinMaxNumber +" connections in "+timeFrameInSeconds+" seconds).\n"+
|
||||
"MODE "+ channel +" +b "+user+"!*@*"); // TODO: consider other ban methods
|
||||
}
|
||||
}
|
|
@ -6,13 +6,13 @@ import InnaIrcBot.ReconnectControl;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PrivateMsgCommander { // TODO: add black list: add users after failed login queries ; temporary ban
|
||||
private String serverName;
|
||||
private ArrayList<String> administrators;
|
||||
private String password;
|
||||
public class PrivateMsgCommander { // TODO: add black list: add users after failed login queries ; temporary ban
|
||||
private final String server;
|
||||
private final String password;
|
||||
private final ArrayList<String> administrators;
|
||||
|
||||
public PrivateMsgCommander(String server, String adminPassword){
|
||||
this.serverName = server;
|
||||
this.server = server;
|
||||
this.administrators = new ArrayList<>();
|
||||
this.password = adminPassword.trim();
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ public class PrivateMsgCommander { // T
|
|||
case "unvoice":
|
||||
if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) {
|
||||
String[] voiceArgs = cmd[1].split("(\\s)|(\t)+?", 2);
|
||||
unvoice(voiceArgs[0], voiceArgs[1]);
|
||||
devoice(voiceArgs[0], voiceArgs[1]);
|
||||
}
|
||||
else
|
||||
tell(simplifyNick(sender), "Pattern: [-v|unvoice] <channel> <user>");
|
||||
|
@ -173,7 +173,7 @@ public class PrivateMsgCommander { // T
|
|||
case "unhop":
|
||||
if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) {
|
||||
String[] hopArgs = cmd[1].split("(\\s)|(\t)+?", 2);
|
||||
unhop(hopArgs[0], hopArgs[1]);
|
||||
dehop(hopArgs[0], hopArgs[1]);
|
||||
}
|
||||
else
|
||||
tell(simplifyNick(sender), "Pattern: [-h|unhop] <channel> <user>");
|
||||
|
@ -191,7 +191,7 @@ public class PrivateMsgCommander { // T
|
|||
case "unop":
|
||||
if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) {
|
||||
String[] args = cmd[1].split("(\\s)|(\t)+?", 2);
|
||||
unop(args[0], args[1]);
|
||||
deop(args[0], args[1]);
|
||||
}
|
||||
else
|
||||
tell(simplifyNick(sender), "Pattern: [-o|unoperator] <channel> <user>");
|
||||
|
@ -238,7 +238,7 @@ public class PrivateMsgCommander { // T
|
|||
}
|
||||
else
|
||||
raw("QUIT :"+message);
|
||||
ReconnectControl.update(serverName, false);
|
||||
ReconnectControl.update(server, false);
|
||||
//ReconnectControl.update(serverName, true);
|
||||
//System.exit(0); // TODO: change to normal exit
|
||||
}
|
||||
|
@ -268,7 +268,7 @@ public class PrivateMsgCommander { // T
|
|||
raw("MODE "+object+" "+mode+" "+user);
|
||||
}
|
||||
private void raw(String rawText){
|
||||
StreamProvider.writeToStream(serverName, rawText);
|
||||
StreamProvider.writeToStream(server, rawText);
|
||||
}
|
||||
private void kick(String chanel, String user, String reason){
|
||||
if (reason == null)
|
||||
|
@ -295,19 +295,19 @@ public class PrivateMsgCommander { // T
|
|||
private void voice(String chanel, String user){
|
||||
cmode(chanel, "+v", user);
|
||||
}
|
||||
private void unvoice(String chanel, String user){
|
||||
private void devoice(String chanel, String user){
|
||||
cmode(chanel, "-v", user);
|
||||
}
|
||||
private void hop(String chanel, String user){
|
||||
cmode(chanel, "+h", user);
|
||||
}
|
||||
private void unhop(String chanel, String user){
|
||||
private void dehop(String chanel, String user){
|
||||
cmode(chanel, "-h", user);
|
||||
}
|
||||
private void op(String chanel, String user){
|
||||
cmode(chanel, "+o", user);
|
||||
}
|
||||
private void unop(String chanel, String user){
|
||||
private void deop(String chanel, String user){
|
||||
cmode(chanel, "-o", user);
|
||||
}
|
||||
private void topic(String channel, String topic){ raw("TOPIC "+channel+" :"+topic); }
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
package InnaIrcBot.Config;
|
||||
|
||||
public class StorageFile {
|
||||
private final String serverName;
|
||||
private final int serverPort;
|
||||
private final String serverPass;
|
||||
private final String[] channels;
|
||||
private final String userNick;
|
||||
private final String userIdent;
|
||||
private final String userRealName;
|
||||
private final String userNickPass;
|
||||
private final String userNickAuthStyle;
|
||||
private final String userMode;
|
||||
private final boolean rejoinOnKick;
|
||||
private final String logDriver;
|
||||
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; }
|
||||
public String getServerPass() { return serverPass; }
|
||||
public String[] getChannels() { return channels; }
|
||||
public String getUserNick() { return userNick; }
|
||||
public String getUserIdent() { return userIdent; }
|
||||
public String getUserRealName() { return userRealName; }
|
||||
public String getUserNickPass() { return userNickPass; }
|
||||
public String getUserNickAuthStyle() { return userNickAuthStyle; }
|
||||
public String getUserMode() { return userMode; }
|
||||
public boolean getRejoinOnKick() { return rejoinOnKick; }
|
||||
public String getLogDriver() { return logDriver; }
|
||||
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,
|
||||
String serverPass,
|
||||
String[] channels,
|
||||
String userNick,
|
||||
String userIdent,
|
||||
String userRealName,
|
||||
String userNickPass,
|
||||
String userNickAuthStyle,
|
||||
String userMode,
|
||||
boolean rejoinOnKick,
|
||||
String logDriver,
|
||||
String[] logDriverParameters,
|
||||
String botAdministratorPassword,
|
||||
String chanelConfigurationsPath,
|
||||
String applicationLogDir){
|
||||
this.serverName = serverName;
|
||||
this.serverPort = serverPort;
|
||||
this.serverPass = serverPass;
|
||||
this.channels = channels;
|
||||
this.userIdent = userIdent;
|
||||
this.userNick = userNick;
|
||||
this.userRealName = userRealName;
|
||||
this.userNickPass = userNickPass;
|
||||
this.userNickAuthStyle = userNickAuthStyle;
|
||||
this.userMode = userMode;
|
||||
this.rejoinOnKick = rejoinOnKick;
|
||||
this.logDriver = logDriver;
|
||||
this.logDriverParameters = logDriverParameters;
|
||||
this.botAdministratorPassword = botAdministratorPassword;
|
||||
this.chanelConfigurationsPath = chanelConfigurationsPath;
|
||||
this.applicationLogDir = applicationLogDir;
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
package InnaIrcBot.Config;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class StorageReader {
|
||||
public static StorageFile readConfig(String pathToFile){ // TODO: NULL or object
|
||||
StorageFile storageObject = null;
|
||||
|
||||
File configFile = new File(pathToFile);
|
||||
|
||||
try (Reader fileReader = new InputStreamReader(new FileInputStream(configFile))) {
|
||||
storageObject = new Gson().fromJson(fileReader, StorageFile.class);
|
||||
return validateConfig(storageObject);
|
||||
} catch (java.io.FileNotFoundException e){
|
||||
System.out.println("Configuration file not found.");
|
||||
return null;
|
||||
} catch (java.io.IOException e){
|
||||
System.out.println("Configuration file is empty or incorrect.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private static StorageFile validateConfig(StorageFile sf){ //TODO: more validation
|
||||
|
||||
if(sf.getServerName().isEmpty()){
|
||||
System.out.println("Server not defined in configuration file.");
|
||||
return null;
|
||||
}
|
||||
else if(sf.getServerPort() <= 0){
|
||||
System.out.println("Server port set incorrectly in configuration file.");
|
||||
return null;
|
||||
}
|
||||
else
|
||||
return sf;
|
||||
}
|
||||
public static void generateDefaultConfig(String pathToFile){
|
||||
File savingFile;
|
||||
if (pathToFile == null) { // no pathToFile? create new in homeDir
|
||||
pathToFile = System.getProperty("user.dir")
|
||||
+File.separator
|
||||
+"myBotConfig.conf";
|
||||
savingFile = new File(pathToFile);
|
||||
}
|
||||
else if(pathToFile.endsWith(File.separator)) { // ends with .../ then create in dir
|
||||
pathToFile = pathToFile + "myBotConfig.conf";
|
||||
savingFile = new File(pathToFile);
|
||||
if (!savingFile.getParentFile().exists())
|
||||
savingFile.getParentFile().mkdirs();
|
||||
}
|
||||
else { // check if it's dir, if yes, then create inside
|
||||
savingFile = new File(pathToFile);
|
||||
if (savingFile.exists() && savingFile.isDirectory()) {
|
||||
pathToFile = pathToFile + File.separator + "myBotConfig.conf";
|
||||
savingFile = new File(pathToFile);
|
||||
}
|
||||
else if (!savingFile.getParentFile().exists())
|
||||
savingFile.getParentFile().mkdirs();
|
||||
}
|
||||
try {
|
||||
savingFile.createNewFile();
|
||||
Writer writerFile = new OutputStreamWriter(new FileOutputStream(savingFile.getAbsolutePath()), StandardCharsets.UTF_8);
|
||||
|
||||
StorageFile storageFileObject = new StorageFile("srv",
|
||||
6667,
|
||||
"",
|
||||
new String[] {"#lpr",
|
||||
"#main"},
|
||||
"user_nick",
|
||||
"ident",
|
||||
"bot",
|
||||
"",
|
||||
"freenode",
|
||||
"ix",
|
||||
true,
|
||||
"Files",
|
||||
new String[] {System.getProperty("user.home")},
|
||||
"pswd",
|
||||
System.getProperty("user.home"),
|
||||
"/var/logs/"
|
||||
);
|
||||
|
||||
Gson writingStorageObject = new GsonBuilder().setPrettyPrinting().create();
|
||||
writingStorageObject.toJson(storageFileObject, writerFile);
|
||||
writerFile.close();
|
||||
System.out.println("Configuration file created: " + pathToFile);
|
||||
} catch (java.io.FileNotFoundException e){
|
||||
System.out.println("Configuration file not found or can't create:\n\t"+e);
|
||||
} catch (java.io.UnsupportedEncodingException e){
|
||||
System.out.println("Unsupported encoding of the configuration file:\n\t"+e);
|
||||
} catch (java.io.IOException e){
|
||||
System.out.println("Unable to write configuration file: I/O exception:\n\t"+e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
package InnaIrcBot;
|
||||
|
||||
import InnaIrcBot.Config.StorageFile;
|
||||
import InnaIrcBot.Config.StorageReader;
|
||||
import InnaIrcBot.ProvidersConsumers.DataProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class Connections {
|
||||
//todo PING Server if not available
|
||||
private HashMap<String, StorageFile> configs;
|
||||
private ArrayList<Thread> connectionsList;
|
||||
|
||||
Connections(String[] args){
|
||||
this.configs = new HashMap<>();
|
||||
this.connectionsList = new ArrayList<>();
|
||||
StorageFile tempConf = null;
|
||||
|
||||
for (int i = 1; i < args.length; i++){
|
||||
if ((tempConf = StorageReader.readConfig(args[i])) != null) {
|
||||
configs.put(tempConf.getServerName(), tempConf);
|
||||
}
|
||||
else
|
||||
System.out.println("Connections->constructor: configuration argument dropped: "+args[i]);
|
||||
}
|
||||
if (!configs.isEmpty()){
|
||||
handleThreads();
|
||||
}
|
||||
else {
|
||||
System.out.println("Connections->constructor: Nothing to execute.");
|
||||
}
|
||||
}
|
||||
private void createAndStartThread(String serverName){
|
||||
//if connectionsList already contains record with name, it should be removed from there first
|
||||
// if there are few configs with same server name then.. fuckup
|
||||
|
||||
Runnable runnableConnection = new DataProvider(configs.get(serverName));
|
||||
Thread threadConnection = new Thread(runnableConnection, serverName);
|
||||
threadConnection.start();
|
||||
connectionsList.add(threadConnection);
|
||||
}
|
||||
private void handleThreads() {
|
||||
// Crate array of threads
|
||||
for (String serverName : configs.keySet())
|
||||
createAndStartThread(serverName);
|
||||
// Watch threads
|
||||
Iterator<Thread> it = connectionsList.iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
System.out.println("\n" + it.next().getName() + "\n");
|
||||
}
|
||||
|
||||
while (!connectionsList.isEmpty()) { // While we have something in connectionList
|
||||
while (it.hasNext()) { // Proceed for every thread in the list
|
||||
Thread curThread = it.next();
|
||||
if (!curThread.isAlive()) // If thread is dead
|
||||
if (ReconnectControl.get(curThread.getName())) { // And ReconnectControl says that this thread shouldn't be dead
|
||||
ReconnectControl.delete(curThread.getName()); // [Try to] remove rule-record from ReconnectControl structure
|
||||
connectionsList.remove(curThread);
|
||||
createAndStartThread(curThread.getName());
|
||||
System.out.println("DEBUG: Thread "+curThread.getName()+" going to restart after unexpected finish.\n\t"+connectionsList.toString());
|
||||
break;
|
||||
} else { // And ReconnectControl says that this thread death expected
|
||||
ReconnectControl.delete(curThread.getName()); // [Try to] remove rule-record from ReconnectControl structure
|
||||
connectionsList.remove(curThread);
|
||||
System.out.println("DEBUG: Thread "+curThread.getName()+" removed from observable list after expected finish.\n\t"+connectionsList.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (connectionsList.isEmpty()) {
|
||||
System.out.println("connectionsList is empty. Exit.");
|
||||
break;
|
||||
}
|
||||
else {
|
||||
it = connectionsList.iterator();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
57
src/main/java/InnaIrcBot/ConnectionsBuilder.java
Normal file
57
src/main/java/InnaIrcBot/ConnectionsBuilder.java
Normal file
|
@ -0,0 +1,57 @@
|
|||
package InnaIrcBot;
|
||||
|
||||
import InnaIrcBot.ProvidersConsumers.DataProvider;
|
||||
import InnaIrcBot.config.ConfigurationFile;
|
||||
import InnaIrcBot.config.ConfigurationManager;
|
||||
|
||||
public class ConnectionsBuilder {
|
||||
private static Connections connections;
|
||||
|
||||
public static Connections getConnections(){
|
||||
return connections;
|
||||
}
|
||||
|
||||
static void buildConnections(String[] pathsToConfigurationFiles){
|
||||
connections = new Connections(pathsToConfigurationFiles);
|
||||
}
|
||||
|
||||
static class Connections {
|
||||
private Connections(String[] pathsToConfigurationFiles){
|
||||
for (String configuration: pathsToConfigurationFiles) {
|
||||
ConfigurationFile configurationFile = registerConfiguration(configuration);
|
||||
if (configuration != null) {
|
||||
startNewConnection(configurationFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ConfigurationFile registerConfiguration(String configuration){
|
||||
try {
|
||||
return ConfigurationManager.readAndSetConfiguration(configuration);
|
||||
}
|
||||
catch (Exception e){
|
||||
System.out.println("Connections->constructor: configuration argument dropped because of "+e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void startNewConnection(ConfigurationFile configurationFile){
|
||||
// if connectionsList already contains record with name, it should be removed from there first
|
||||
// if there are few configs with same server name then.. fuckup
|
||||
DataProvider runnableConnection = new DataProvider(configurationFile);
|
||||
Thread threadConnection = new Thread(runnableConnection);
|
||||
threadConnection.start();
|
||||
}
|
||||
|
||||
public void startNewConnection(String serverName){
|
||||
try {
|
||||
ConfigurationFile configurationFile = ConfigurationManager.getConfiguration(serverName);
|
||||
startNewConnection(configurationFile);
|
||||
}
|
||||
catch (Exception e){
|
||||
System.out.println("Unable to start new connectionL "+e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
package InnaIrcBot;
|
||||
|
||||
public class GlobalData {
|
||||
private static final String version = "InnaIrcBot v0.7 \"Комсомолец\"";
|
||||
private static final String version = "InnaIrcBot v0.8 \"Коммунарка\"";
|
||||
public static synchronized String getAppVersion(){
|
||||
return version;
|
||||
}
|
||||
public static final int CHANNEL_QUEUE_CAPACITY = 500;
|
||||
}
|
||||
|
|
23
src/main/java/InnaIrcBot/IrcChannel.java
Normal file
23
src/main/java/InnaIrcBot/IrcChannel.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package InnaIrcBot;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
public class IrcChannel {
|
||||
private final String name;
|
||||
private final BlockingQueue<String> channelQueue;
|
||||
|
||||
public IrcChannel(String channelName){
|
||||
this.name = channelName;
|
||||
this.channelQueue = new ArrayBlockingQueue<>(GlobalData.CHANNEL_QUEUE_CAPACITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public BlockingQueue<String> getChannelQueue() {
|
||||
return channelQueue;
|
||||
}
|
||||
}
|
|
@ -3,48 +3,56 @@ package InnaIrcBot.LogDriver;
|
|||
import java.util.HashMap;
|
||||
|
||||
public class BotDriver {
|
||||
private static HashMap<String, String[][]> serverDriver = new HashMap<>();
|
||||
|
||||
private static HashMap<String, BotSystemWorker> systemLogWorkerMap = new HashMap<>();
|
||||
private final static HashMap<String, String[][]> serverDriver = new HashMap<>();
|
||||
private final static HashMap<String, BotSystemWorker> 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, 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
|
||||
if (driver == null)
|
||||
return false;
|
||||
if (driver.isEmpty())
|
||||
return false;
|
||||
if (driverParams.length == 0)
|
||||
return false;
|
||||
if (driverParams[0] == null)
|
||||
return false;
|
||||
if (driverParams[0].isEmpty())
|
||||
return false;
|
||||
|
||||
String[][] drvAndParams = {
|
||||
{driver},
|
||||
driverParams
|
||||
};
|
||||
serverDriver.put(serverName, drvAndParams);
|
||||
systemLogWorkerMap.put(serverName, new BotSystemWorker(serverName, applicationLogDir));
|
||||
return true;
|
||||
}
|
||||
public static synchronized Worker getWorker(String serverName, String chanelName){
|
||||
if (serverDriver.containsKey(serverName)) {
|
||||
switch (serverDriver.get(serverName)[0][0].toLowerCase()) {
|
||||
|
||||
public static synchronized Worker getWorker(String server, String channel){
|
||||
if (serverDriver.containsKey(server)) {
|
||||
switch (serverDriver.get(server)[0][0].toLowerCase()) {
|
||||
case "files":
|
||||
BotFilesWorker botFilesWorker = new BotFilesWorker(serverName, serverDriver.get(serverName)[1], chanelName);
|
||||
return validateConstancy(botFilesWorker, serverName, chanelName);
|
||||
BotFilesWorker botFilesWorker = new BotFilesWorker(server, serverDriver.get(server)[1], channel);
|
||||
return validateConsistancy(botFilesWorker, server, channel);
|
||||
case "sqlite":
|
||||
BotSQLiteWorker botSQLiteWorker = new BotSQLiteWorker(serverName, serverDriver.get(serverName)[1], chanelName);
|
||||
return validateConstancy(botSQLiteWorker, serverName, chanelName);
|
||||
BotSQLiteWorker botSQLiteWorker = new BotSQLiteWorker(server, serverDriver.get(server)[1], channel);
|
||||
return validateConsistancy(botSQLiteWorker, server, channel);
|
||||
case "mongodb":
|
||||
BotMongoWorker botMongoWorker = new BotMongoWorker(serverName, serverDriver.get(serverName)[1], chanelName);
|
||||
return validateConstancy(botMongoWorker, serverName, chanelName);
|
||||
BotMongoWorker botMongoWorker = new BotMongoWorker(server, serverDriver.get(server)[1], channel);
|
||||
return validateConsistancy(botMongoWorker, server, channel);
|
||||
case "zero":
|
||||
return new BotZeroWorker();
|
||||
default:
|
||||
System.out.println("BotDriver->getWorker(): Configuration issue: can't find required driver \""
|
||||
+serverDriver.get(serverName)[0][0]
|
||||
+serverDriver.get(server)[0][0]
|
||||
+"\".Using \"ZeroWorker\".");
|
||||
return new BotZeroWorker();
|
||||
}
|
||||
}
|
||||
System.out.println("BotDriver->getWorker(): Unknown issue: Channel exists for non-existing server.\n\tUsing ZeroWorker.");
|
||||
System.out.println("Issue on BotDriver->getWorker(): Channel requested 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
|
||||
|
@ -54,15 +62,13 @@ public class BotDriver {
|
|||
return systemLogWorkerMap.get(serverName);
|
||||
}
|
||||
|
||||
private static Worker validateConstancy(Worker worker, String srv, String chan){ // synchronized?
|
||||
private static Worker validateConsistancy(Worker worker, String server, String channel){ // 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();
|
||||
}
|
||||
System.out.println("BotDriver->validateConstancy(): Unable to use "
|
||||
+worker.getClass().getSimpleName()+" for "+server+"/"+channel
|
||||
+". Using ZeroWorker instead.");
|
||||
return new BotZeroWorker();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,57 +9,63 @@ import java.time.format.DateTimeFormatter;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
public class BotFilesWorker implements Worker {
|
||||
private String filePath;
|
||||
private boolean consistent = false;
|
||||
private DateTimeFormatter dateFormat;
|
||||
|
||||
private LocalDate fileWriterDay;
|
||||
private final String channel;
|
||||
private String filePath;
|
||||
private final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
|
||||
private LocalDate dateOnFile;
|
||||
private FileWriter fileWriter;
|
||||
|
||||
private String ircServer; // hold for debug only
|
||||
private boolean consistent;
|
||||
|
||||
public BotFilesWorker(String server, String[] driverParameters, String channel){
|
||||
ircServer = server;
|
||||
dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
|
||||
this.channel = channel.replaceAll(File.separator, ",");
|
||||
|
||||
channel = channel.replaceAll(File.separator, ",");
|
||||
formatFilePath(server, driverParameters);
|
||||
|
||||
String dirLocation = driverParameters[0].trim();
|
||||
if (dirLocation.endsWith(File.separator))
|
||||
dirLocation = dirLocation+server;
|
||||
else
|
||||
dirLocation = dirLocation+File.separator+server;
|
||||
|
||||
this.filePath = dirLocation+File.separator+channel;
|
||||
|
||||
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.
|
||||
createServerFolder();
|
||||
createFileWriter();
|
||||
consistent = true;
|
||||
} 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;
|
||||
System.out.println("BotFilesWorker (@"+server+")->constructor(): Failure:\n" + e.getMessage());
|
||||
}
|
||||
if (!dir.exists()) {
|
||||
System.out.println("BotFilesWorker (@"+server+")->constructor() failed:\n\tUnable to create directory to store files: " + dirLocation);
|
||||
}
|
||||
|
||||
private void formatFilePath(String server, String[] driverParameters){
|
||||
String dirLocation = driverParameters[0].trim(); // TODO: MOVE trim() out of here
|
||||
|
||||
if (! dirLocation.endsWith(File.separator))
|
||||
dirLocation += File.separator;
|
||||
|
||||
this.filePath = dirLocation+server+File.separator;
|
||||
}
|
||||
|
||||
private void createServerFolder() throws Exception{
|
||||
final File file = new File(filePath);
|
||||
|
||||
if (file.exists()){
|
||||
if (file.isDirectory())
|
||||
return;
|
||||
else
|
||||
throw new Exception("BotFilesWorker->createServerFolder() "+filePath+" is file while directory expected.");
|
||||
}
|
||||
|
||||
if (file.mkdirs())
|
||||
return;
|
||||
}
|
||||
|
||||
this.consistent = resetFileWriter(false);
|
||||
throw new Exception("BotFilesWorker->createServerFolder() Can't create directory: "+filePath);
|
||||
}
|
||||
|
||||
private boolean resetFileWriter(boolean reassign){
|
||||
try {
|
||||
if (reassign)
|
||||
this.fileWriter.close();
|
||||
this.fileWriterDay = LocalDate.now();
|
||||
this.fileWriter = new FileWriter(this.filePath+"_"+LocalDate.now().toString()+".txt", true);
|
||||
return true;
|
||||
}
|
||||
catch (java.io.IOException e){
|
||||
System.out.println("BotFilesWorker (@"+ircServer+")->resetFileWriter() failed:\n\tCan't create file to store logs: "+this.filePath);
|
||||
return false;
|
||||
}
|
||||
private void resetFileWriter() throws IOException{
|
||||
fileWriter.close();
|
||||
createFileWriter();
|
||||
}
|
||||
private void createFileWriter() throws IOException{
|
||||
dateOnFile = LocalDate.now();
|
||||
File newFile = new File(filePath+channel+"_"+ dateOnFile +".txt");
|
||||
fileWriter = new FileWriter(newFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConsistent() {
|
||||
return consistent;
|
||||
|
@ -70,79 +76,73 @@ public class BotFilesWorker implements Worker {
|
|||
* argument[1] should be always 'subject'
|
||||
* */
|
||||
@Override
|
||||
public boolean logAdd(String event, String initiatorArg, String messageArg) {
|
||||
public boolean logAdd(String event, String initiator, String message) {
|
||||
switch (event){
|
||||
case "PRIVMSG":
|
||||
PRIVMSG(initiatorArg, messageArg);
|
||||
PRIVMSG(initiator, message);
|
||||
break;
|
||||
case "JOIN":
|
||||
JOIN(initiatorArg, messageArg);
|
||||
JOIN(initiator, message);
|
||||
break;
|
||||
case "MODE":
|
||||
MODE(initiatorArg, messageArg);
|
||||
MODE(initiator, message);
|
||||
break;
|
||||
case "KICK":
|
||||
KICK(initiatorArg, messageArg);
|
||||
KICK(initiator, message);
|
||||
break;
|
||||
case "PART":
|
||||
PART(initiatorArg, messageArg);
|
||||
PART(initiator, message);
|
||||
break;
|
||||
case "QUIT":
|
||||
QUIT(initiatorArg, messageArg);
|
||||
QUIT(initiator, message);
|
||||
break;
|
||||
case "NICK":
|
||||
NICK(initiatorArg, messageArg);
|
||||
NICK(initiator, message);
|
||||
break;
|
||||
case "TOPIC":
|
||||
TOPIC(initiatorArg, messageArg);
|
||||
TOPIC(initiator, message);
|
||||
break;
|
||||
default:
|
||||
this.prettyPrint("["+LocalTime.now().format(dateFormat)+"] "+event+" "+initiatorArg+" "+messageArg+"\n"); // TODO: QA @ big data
|
||||
prettyPrint("["+LocalTime.now().format(dateFormat)+"] "+event+" "+initiator+" "+message+"\n"); // TODO: QA @ big data
|
||||
break;
|
||||
}
|
||||
return consistent;
|
||||
}
|
||||
private void prettyPrint(String string){
|
||||
//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();
|
||||
try {
|
||||
if (LocalDate.now().isAfter(dateOnFile)) {
|
||||
resetFileWriter();
|
||||
}
|
||||
//}
|
||||
fileWriter.write(string);
|
||||
fileWriter.flush();
|
||||
} catch (Exception e){
|
||||
System.out.println("BotFilesWorker->prettyPrint() failed\n" +
|
||||
"\tUnable to write logs to " + this.filePath + " "+e.getMessage());
|
||||
close();
|
||||
consistent = false;
|
||||
}
|
||||
}
|
||||
private String genDate(){
|
||||
private String getCurrentTimestamp(){
|
||||
return "["+LocalTime.now().format(dateFormat)+"] ";
|
||||
}
|
||||
private String getUserNameOnly(String userNameFull){return userNameFull.replaceAll("!.+$", "");}
|
||||
private String getUserNameAndHost(String userNameFull){return userNameFull.replaceAll("!.+$", "")+" [!"+userNameFull.replaceAll("^.+!", "")+"] ";}
|
||||
private String getUserNameOnly(String userNameFull){
|
||||
return userNameFull.replaceAll("!.+$", "");
|
||||
}
|
||||
private String getUserNameAndHost(String userNameFull){
|
||||
return userNameFull.replaceAll("!.+$", "")+" [!"+userNameFull.replaceAll("^.+!", "")+"] ";
|
||||
}
|
||||
|
||||
private void PRIVMSG(String initiatorArg, String messageArg){
|
||||
String msg = messageArg.substring(messageArg.indexOf(":")+1);
|
||||
if (!Pattern.matches("^\\u0001ACTION .+\\u0001", msg)){
|
||||
this.prettyPrint(genDate()+"<"+getUserNameOnly(initiatorArg)+"> "+msg+"\n");
|
||||
}
|
||||
else {
|
||||
this.prettyPrint(genDate()+getUserNameOnly(initiatorArg)+msg.replaceAll("(^\\u0001ACTION)|(\\u0001$)","")+"\n");
|
||||
|
||||
if (Pattern.matches("^\\u0001ACTION .+\\u0001", msg)){
|
||||
prettyPrint(getCurrentTimestamp()+getUserNameOnly(initiatorArg)+msg.replaceAll("(^\\u0001ACTION)|(\\u0001$)","")+"\n");
|
||||
return;
|
||||
}
|
||||
prettyPrint(getCurrentTimestamp()+"<"+getUserNameOnly(initiatorArg)+"> "+msg+"\n");
|
||||
}
|
||||
private void JOIN(String initiatorArg, String messageArg){
|
||||
this.prettyPrint(genDate()+">> "+getUserNameAndHost(initiatorArg)+"joined "+messageArg+"\n");
|
||||
prettyPrint(getCurrentTimestamp()+">> "+getUserNameAndHost(initiatorArg)+"joined "+messageArg+"\n");
|
||||
}
|
||||
private void MODE(String initiatorArg, String messageArg){
|
||||
String initiatorChain;
|
||||
|
@ -150,33 +150,38 @@ public class BotFilesWorker implements Worker {
|
|||
initiatorChain = getUserNameAndHost(initiatorArg)+"set";
|
||||
else
|
||||
initiatorChain = initiatorArg+" set";
|
||||
this.prettyPrint(genDate()+"-!- "+initiatorChain+messageArg.substring(messageArg.indexOf(" "))+"\n");
|
||||
|
||||
prettyPrint(getCurrentTimestamp()+"-!- "+initiatorChain + messageArg.substring(messageArg.indexOf(" "))+"\n");
|
||||
}
|
||||
private void KICK(String initiatorArg, String messageArg){
|
||||
this.prettyPrint(genDate()+"!<< "+messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")+
|
||||
prettyPrint(getCurrentTimestamp()+"!<< "+messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")+
|
||||
" kicked by "+getUserNameAndHost(initiatorArg)+"with reason: "+messageArg.replaceAll("^.+?:", "")+"\n");
|
||||
}
|
||||
private void PART(String initiatorArg, String messageArg){
|
||||
this.prettyPrint(genDate()+"<< "+getUserNameAndHost(initiatorArg)+"parted: "+messageArg.replaceAll("^.+?:","")+"\n");
|
||||
prettyPrint(getCurrentTimestamp()+"<< "+getUserNameAndHost(initiatorArg)+"parted: "
|
||||
+ messageArg.replaceAll("^.+?:","")+"\n");
|
||||
}
|
||||
private void QUIT(String initiatorArg, String messageArg){
|
||||
this.prettyPrint(genDate()+"<< "+getUserNameAndHost(initiatorArg)+"quit: "+messageArg.replaceAll("^.+?:","")+"\n");
|
||||
prettyPrint(getCurrentTimestamp()+"<< "+getUserNameAndHost(initiatorArg)+"quit: "
|
||||
+ messageArg.replaceAll("^.+?:","")+"\n");
|
||||
}
|
||||
private void NICK(String initiatorArg, String messageArg){
|
||||
this.prettyPrint(genDate()+"-!- "+getUserNameAndHost(initiatorArg)+"changed nick to: "+messageArg+"\n");
|
||||
prettyPrint(getCurrentTimestamp()+"-!- "+getUserNameAndHost(initiatorArg)+"changed nick to: "+messageArg+"\n");
|
||||
}
|
||||
private void TOPIC(String initiatorArg, String messageArg) {
|
||||
this.prettyPrint(genDate()+"-!- "+getUserNameAndHost(initiatorArg)+"has changed topic to: "+messageArg.replaceAll("^.+?:", "")+"\n");
|
||||
prettyPrint(getCurrentTimestamp()+"-!- "+getUserNameAndHost(initiatorArg)+"has changed topic to: "
|
||||
+ messageArg.replaceAll("^.+?:", "")+"\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
if (fileWriter !=null)
|
||||
fileWriter.close();
|
||||
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.
|
||||
catch (NullPointerException ignore) {}
|
||||
catch (IOException e){
|
||||
System.out.println("BotFilesWorker->close() failed\n" +
|
||||
"\tUnable to properly close file: "+this.filePath); // Live with it.
|
||||
}
|
||||
this.consistent = false;
|
||||
}
|
||||
|
|
|
@ -17,73 +17,74 @@ import java.util.concurrent.TimeUnit;
|
|||
* 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;
|
||||
public class BotMongoWorker implements Worker { //TODO consider skipping checks if server already added.
|
||||
private final static Map<String, MongoClient> serversMap = Collections.synchronizedMap(new HashMap<>());
|
||||
private final String server;
|
||||
private MongoCollection<Document> collection;
|
||||
private boolean consistent = false;
|
||||
private boolean consistent;
|
||||
|
||||
public BotMongoWorker(String ircServer, String[] driverParameters, String channel){
|
||||
this.ircServer = ircServer;
|
||||
public BotMongoWorker(String server, String[] driverParameters, String channel){
|
||||
this.server = server;
|
||||
|
||||
if (driverParameters.length < 2)
|
||||
return;
|
||||
if (driverParameters[0].isEmpty())
|
||||
return;
|
||||
if (driverParameters[1].isEmpty())
|
||||
return;
|
||||
|
||||
String mongoHostAddress = driverParameters[0];
|
||||
String mongoDBName = driverParameters[1];
|
||||
|
||||
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)){
|
||||
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";
|
||||
}
|
||||
|
||||
if (! serversMap.containsKey(server)){
|
||||
/* // Leave this validations for better times.
|
||||
CommandListener mongoCommandListener = new CommandListener() {
|
||||
@Override
|
||||
public void commandStarted(CommandStartedEvent commandStartedEvent) {
|
||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandStarted");
|
||||
System.out.println("BotMongoWorker (@"+this.server+"): C: commandStarted");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commandSucceeded(CommandSucceededEvent commandSucceededEvent) {
|
||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandSucceeded");
|
||||
System.out.println("BotMongoWorker (@"+this.server+"): C: commandSucceeded");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commandFailed(CommandFailedEvent commandFailedEvent) {
|
||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandFailed");
|
||||
System.out.println("BotMongoWorker (@"+this.server+"): C: commandFailed");
|
||||
//consistent = false;
|
||||
//close(ircServer); // ircServer recieved by constructor, not this.ircServer
|
||||
//close(server); // server recieved by constructor, not this.server
|
||||
}
|
||||
};
|
||||
*/
|
||||
ServerListener mongoServerListener = new ServerListener() {
|
||||
@Override
|
||||
public void serverOpening(ServerOpeningEvent serverOpeningEvent) {
|
||||
System.out.println("BotMongoWorker (@"+ircServer+"): ServerListener: Server opened successfully: "+serverOpeningEvent.getServerId());
|
||||
System.out.println("BotMongoWorker (@"+server+"): ServerListener: Server opened successfully: "+serverOpeningEvent.getServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverClosed(ServerClosedEvent serverClosedEvent) {
|
||||
System.out.println("BotMongoWorker (@"+ircServer+"): ServerListener: Server has been closed");
|
||||
System.out.println("BotMongoWorker (@"+server+"): 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): "
|
||||
close(server); // server recieved by constructor, not this.server
|
||||
System.out.println("BotMongoWorker (@"+server+"): ServerListener: Server description changed (exception occurs): "
|
||||
+ serverDescriptionChangedEvent.getNewDescription().getException());
|
||||
}
|
||||
}
|
||||
|
@ -91,111 +92,98 @@ public class BotMongoWorker implements Worker { //TODO consi
|
|||
|
||||
MongoClientSettings MCS = MongoClientSettings.builder()
|
||||
// .addCommandListener(mongoCommandListener)
|
||||
.applyConnectionString(new ConnectionString("mongodb://"+mongoHostAddr))
|
||||
.applyConnectionString(new ConnectionString("mongodb://"+mongoHostAddress))
|
||||
.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);
|
||||
serversMap.put(server, mongoClient);
|
||||
}
|
||||
|
||||
MongoDatabase mongoDB = serversMap.get(ircServer).getDatabase(mongoDBName);
|
||||
collection = mongoDB.getCollection(ircServer + channel);
|
||||
MongoDatabase mongoDB = serversMap.get(server).getDatabase(mongoDBName);
|
||||
collection = mongoDB.getCollection(server + 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);
|
||||
close(server);
|
||||
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
|
||||
System.out.println("BotMongoWorker (@"+this.server +"): Command exception. Check if username/password set correctly.");
|
||||
close(server); // server received by constructor, not this.server
|
||||
} catch (MongoTimeoutException mte) {
|
||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): Timeout exception.");
|
||||
close(ircServer); // ircServer received by constructor, not this.ircServer
|
||||
System.out.println("BotMongoWorker (@"+this.server +"): Timeout exception.");
|
||||
close(server); // server received by constructor, not this.server
|
||||
}catch (MongoException me){
|
||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): MongoDB Exception.");
|
||||
close(ircServer); // ircServer received by constructor, not this.ircServer
|
||||
System.out.println("BotMongoWorker (@"+this.server +"): MongoDB Exception.");
|
||||
close(server); // server received by constructor, not this.server
|
||||
} catch (IllegalStateException ise){
|
||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): Illegal state exception: MongoDB server already closed (not an issue).");
|
||||
System.out.println("BotMongoWorker (@"+this.server +"): 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);
|
||||
}
|
||||
}
|
||||
ThingToCloseOnDie thing = () -> {
|
||||
if (serversMap.containsKey(server)) {
|
||||
serversMap.get(server).close();
|
||||
serversMap.remove(server);
|
||||
}
|
||||
};
|
||||
|
||||
BotDriver.getSystemWorker(ircServer).registerInSystemWorker(thing);
|
||||
BotDriver.getSystemWorker(server).registerInSystemWorker(thing);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logAdd(String event, String initiatorArg, String messageArg) {
|
||||
public boolean logAdd(String event, String initiator, String message) {
|
||||
Document document = new Document("date", getDate())
|
||||
.append("event", event)
|
||||
.append("initiator", initiatorArg);
|
||||
.append("initiator", initiator);
|
||||
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);
|
||||
document.append("message1", message.replaceAll("^.+?:", ""));
|
||||
break;
|
||||
case "MODE":
|
||||
document.append("message1", messageArg.replaceAll("(^(.+?\\s){1})|(\\s.+$)",""));
|
||||
document.append("message2", messageArg.replaceAll("^(.+?\\s){2}", ""));
|
||||
document.append("message1", message.replaceAll("(^(.+?\\s){1})|(\\s.+$)",""));
|
||||
document.append("message2", message.replaceAll("^(.+?\\s){2}", ""));
|
||||
break;
|
||||
case "KICK":
|
||||
document.append("message1", messageArg.replaceAll("^.+?:", ""));
|
||||
document.append("message2", messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", ""));
|
||||
document.append("message1", message.replaceAll("^.+?:", ""));
|
||||
document.append("message2", message.replaceAll("(^.+?\\s)|(\\s.+$)", ""));
|
||||
break;
|
||||
case "PRIVMSG":
|
||||
document.append("message1", messageArg.replaceAll("^:", ""));
|
||||
//preparedStatement.setString(5,null);
|
||||
document.append("message1", message.replaceAll("^:", ""));
|
||||
break;
|
||||
case "NICK":
|
||||
case "JOIN":
|
||||
default:
|
||||
document.append("message1", messageArg);
|
||||
//preparedStatement.setString(5,null);
|
||||
document.append("message1", message);
|
||||
break;
|
||||
}
|
||||
try {
|
||||
collection.insertOne(document); // TODO: call finalize?
|
||||
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.");
|
||||
System.out.println("BotMongoWorker (@"+this.server +")->logAdd(): Command exception. Check if username/password set correctly.");
|
||||
this.close();
|
||||
} catch (MongoTimeoutException mte) {
|
||||
System.out.println("BotMongoWorker (@"+this.ircServer+")->logAdd(): Timeout exception.");
|
||||
System.out.println("BotMongoWorker (@"+this.server +")->logAdd(): Timeout exception.");
|
||||
this.close();
|
||||
}catch (MongoException me){
|
||||
System.out.println("BotMongoWorker (@"+this.ircServer+")->logAdd(): MongoDB Exception.");
|
||||
System.out.println("BotMongoWorker (@"+this.server +")->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).");
|
||||
System.out.println("BotMongoWorker (@"+this.server +")->logAdd(): Illegal state exception: MongoDB server already closed (not an issue).");
|
||||
this.close();
|
||||
}
|
||||
return consistent;
|
||||
|
@ -214,7 +202,7 @@ public class BotMongoWorker implements Worker { //TODO consi
|
|||
if (serversMap.containsKey(server)) {
|
||||
serversMap.get(server).close();
|
||||
serversMap.remove(server);
|
||||
System.out.println("BotMongoWorker (@"+this.ircServer+")->close() [forced by listeners]");
|
||||
System.out.println("BotMongoWorker (@"+this.server +")->close() [forced by listeners]");
|
||||
}
|
||||
consistent = false;
|
||||
}
|
||||
|
|
|
@ -155,37 +155,37 @@ public class BotSQLiteWorker implements Worker {
|
|||
public boolean isConsistent() {return consistent; }
|
||||
|
||||
@Override
|
||||
public boolean logAdd(String event, String initiatorArg, String messageArg) {
|
||||
public boolean logAdd(String event, String initiator, String message) {
|
||||
try {
|
||||
preparedStatement.setLong(1, getDate());
|
||||
preparedStatement.setString(2, event);
|
||||
preparedStatement.setString(3, initiatorArg);
|
||||
preparedStatement.setString(3, initiator);
|
||||
switch (event) {
|
||||
case "NICK":
|
||||
case "JOIN":
|
||||
preparedStatement.setString(4, messageArg);
|
||||
preparedStatement.setString(4, message);
|
||||
preparedStatement.setString(5, null);
|
||||
break;
|
||||
case "PART":
|
||||
case "QUIT":
|
||||
case "TOPIC":
|
||||
preparedStatement.setString(4, messageArg.replaceAll("^.+?:", ""));
|
||||
preparedStatement.setString(4, message.replaceAll("^.+?:", ""));
|
||||
preparedStatement.setString(5, null);
|
||||
break;
|
||||
case "MODE":
|
||||
preparedStatement.setString(4, messageArg.replaceAll("(^(.+?\\s){1})|(\\s.+$)",""));
|
||||
preparedStatement.setString(5, messageArg.replaceAll("^(.+?\\s){2}", ""));
|
||||
preparedStatement.setString(4, message.replaceAll("(^(.+?\\s){1})|(\\s.+$)",""));
|
||||
preparedStatement.setString(5, message.replaceAll("^(.+?\\s){2}", ""));
|
||||
break;
|
||||
case "KICK":
|
||||
preparedStatement.setString(4, messageArg.replaceAll("^.+?:", ""));
|
||||
preparedStatement.setString(5, messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", ""));
|
||||
preparedStatement.setString(4, message.replaceAll("^.+?:", ""));
|
||||
preparedStatement.setString(5, message.replaceAll("(^.+?\\s)|(\\s.+$)", ""));
|
||||
break;
|
||||
case "PRIVMSG":
|
||||
preparedStatement.setString(4, messageArg.replaceAll("^:", ""));
|
||||
preparedStatement.setString(4, message.replaceAll("^:", ""));
|
||||
preparedStatement.setString(5,null);
|
||||
break;
|
||||
default:
|
||||
preparedStatement.setString(4, messageArg);
|
||||
preparedStatement.setString(4, message);
|
||||
preparedStatement.setString(5,null);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -9,48 +9,43 @@ import java.time.format.DateTimeFormatter;
|
|||
public class BotSystemWorker implements SystemWorker{
|
||||
|
||||
private FileWriter fileWriter;
|
||||
private DateTimeFormatter dateFormat;
|
||||
private final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
|
||||
private ThingToCloseOnDie thingToCloseOnDie; // call .die() method of this classes when this (system log class) dies.
|
||||
|
||||
String ircServer;
|
||||
private final String server;
|
||||
|
||||
private boolean consistent = false;
|
||||
|
||||
public BotSystemWorker(String ircServer, String appLogDir){
|
||||
this.ircServer = ircServer;
|
||||
this.dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
|
||||
|
||||
public BotSystemWorker(String server, String appLogDir){
|
||||
this.server = server;
|
||||
|
||||
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/";
|
||||
}
|
||||
appLogDir = System.getProperty("java.io.tmpdir")+File.separator+"innaircbot"+File.separator;
|
||||
}
|
||||
else if (! appLogDir.endsWith(File.separator)) {
|
||||
appLogDir += File.separator;
|
||||
}
|
||||
if (!appLogDir.endsWith(File.separator))
|
||||
appLogDir = appLogDir+File.separator;
|
||||
|
||||
appLogDir = appLogDir+ircServer;
|
||||
appLogDir += server;
|
||||
|
||||
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);
|
||||
if (! logFile.getParentFile().exists()) {
|
||||
if (! logFile.getParentFile().mkdirs()){
|
||||
System.out.println("BotSystemWorker (@"+server+")->constructor() failed:\n" +
|
||||
"\tUnable to create sub-directory(-ies) to store log file: " + appLogDir);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fileWriter = new FileWriter(logFile, true);
|
||||
consistent = true;
|
||||
} catch (SecurityException e){
|
||||
System.out.println("BotSystemWorker (@"+server+")->constructor() failed.\n" +
|
||||
"\tUnable to create sub-directory(-ies) to store logs file ("+appLogDir+"):\n\t"+e.getMessage());
|
||||
} catch (IOException oie){
|
||||
System.out.println("BotSystemWorker (@"+ircServer+")->constructor() failed:\n\tUnable to open file to store logs: " + appLogDir);
|
||||
System.out.println("BotSystemWorker (@"+server+")->constructor() failed:\n" +
|
||||
"\tUnable to open file to store logs: " + appLogDir + " "+ oie.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,22 +59,14 @@ public class BotSystemWorker implements SystemWorker{
|
|||
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);
|
||||
} catch (Exception e) { // ??? No ideas. Just in case. Consider removing.
|
||||
System.out.println("BotSystemWorker (@" + server + ")->logAdd() failed\n\tUnable to write logs of because of exception:\n\t" + e.getMessage());
|
||||
//this.close();
|
||||
consistent = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
System.out.println(genDate() + event + " " + initiatorArg + " " + messageArg + "\n");
|
||||
}
|
||||
System.out.println(genDate() + event + " " + initiatorArg + " " + messageArg + "\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,14 +80,11 @@ public class BotSystemWorker implements SystemWorker{
|
|||
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.
|
||||
}
|
||||
|
||||
try {
|
||||
fileWriter.close();
|
||||
}
|
||||
catch (IOException | NullPointerException ignore){}
|
||||
consistent = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ public class BotZeroWorker implements Worker{
|
|||
public boolean isConsistent() {return true;}
|
||||
|
||||
@Override
|
||||
public boolean logAdd(String event, String initiatorArg, String messageArg) { return true; }
|
||||
public boolean logAdd(String event, String initiator, String message) { return true; }
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
|
|
@ -6,8 +6,8 @@ public interface Worker {
|
|||
boolean isConsistent();
|
||||
|
||||
boolean logAdd(String event,
|
||||
String initiatorArg,
|
||||
String messageArg);
|
||||
String initiator,
|
||||
String message);
|
||||
|
||||
void close();
|
||||
}
|
||||
|
|
16
src/main/java/InnaIrcBot/Main.java
Normal file
16
src/main/java/InnaIrcBot/Main.java
Normal file
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* InnaIrcBot
|
||||
* @author Dmitry Isaenko
|
||||
* Russia, 2018-2020.
|
||||
* */
|
||||
package InnaIrcBot;
|
||||
|
||||
public class Main {
|
||||
//TODO: flood control
|
||||
//TODO: setDaemon(true)
|
||||
//TODO: multiple connections to one server not allowed
|
||||
|
||||
public static void main(String[] args){
|
||||
new BotStart(args);
|
||||
}
|
||||
}
|
|
@ -1,82 +1,86 @@
|
|||
package InnaIrcBot.ProvidersConsumers;
|
||||
|
||||
import InnaIrcBot.Commanders.ChanelCommander;
|
||||
import InnaIrcBot.GlobalData;
|
||||
import InnaIrcBot.IrcChannel;
|
||||
import InnaIrcBot.LogDriver.BotDriver;
|
||||
import InnaIrcBot.LogDriver.Worker;
|
||||
import InnaIrcBot.config.ConfigurationManager;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
|
||||
public class ChanConsumer implements Runnable {
|
||||
private BufferedReader reader;
|
||||
private String serverName;
|
||||
private String channelName;
|
||||
private final BlockingQueue<String> chanConsumerQueue;
|
||||
private final String serverName;
|
||||
private final String channelName;
|
||||
private Worker writerWorker;
|
||||
private ArrayList<String> userList;
|
||||
private String nick;
|
||||
private boolean rejoin;
|
||||
private Map<String, PrintWriter> chanList;
|
||||
private String configFilePath;
|
||||
private final boolean rejoin;
|
||||
private final Map<String, IrcChannel> channels;
|
||||
|
||||
private PrintWriter chanelCommanderPipe;
|
||||
private Thread channelCommanderThread;
|
||||
private BlockingQueue<String> queue;
|
||||
|
||||
private boolean endThread = false;
|
||||
|
||||
ChanConsumer(BufferedReader streamReader, String serverName, String channelName, String ownNick, String[] usersOnChan, boolean rejoinAlways, Map<String, PrintWriter> map, String configFilePath){
|
||||
this.reader = streamReader;
|
||||
ChanConsumer(String serverName,
|
||||
IrcChannel thisIrcChannel,
|
||||
String ownNick,
|
||||
Map<String, IrcChannel> channels) throws Exception{
|
||||
this.chanConsumerQueue = thisIrcChannel.getChannelQueue();
|
||||
this.serverName = serverName;
|
||||
this.channelName = channelName;
|
||||
this.channelName = thisIrcChannel.toString();
|
||||
this.writerWorker = BotDriver.getWorker(serverName, channelName);
|
||||
this.userList = new ArrayList<>();
|
||||
this.userList.addAll(Arrays.asList(usersOnChan));
|
||||
this.nick = ownNick;
|
||||
this.rejoin = rejoinAlways;
|
||||
this.chanList = map;
|
||||
this.configFilePath = configFilePath;
|
||||
this.rejoin = ConfigurationManager.getConfiguration(serverName).getRejoinOnKick();
|
||||
this.channels = channels;
|
||||
// Create chanel commander thread, get pipe
|
||||
this.chanelCommanderPipe = getChanelCommander();
|
||||
getChanelCommander(
|
||||
ConfigurationManager.getConfiguration(serverName).getChanelConfigurationsPath()
|
||||
);
|
||||
}
|
||||
// Create ChanelCommander
|
||||
private void getChanelCommander(String chanelConfigurationsPath){
|
||||
this.queue = new ArrayBlockingQueue<>(GlobalData.CHANNEL_QUEUE_CAPACITY);
|
||||
ChanelCommander commander = new ChanelCommander(queue, serverName, channelName, chanelConfigurationsPath);
|
||||
this.channelCommanderThread = new Thread(commander);
|
||||
this.channelCommanderThread.start();
|
||||
}
|
||||
|
||||
public void run(){
|
||||
String data;
|
||||
String[] dataStrings;
|
||||
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] THREAD "+serverName+":"+this.channelName +" started"); // TODO:REMOVE DEBUG
|
||||
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] ChanConsumer thread "+serverName+":"+this.channelName +" started"); // TODO:REMOVE DEBUG
|
||||
try {
|
||||
while ((data = reader.readLine()) != null) {
|
||||
while (! endThread) {
|
||||
data = chanConsumerQueue.take();
|
||||
dataStrings = data.split(" ",3);
|
||||
|
||||
if (!trackUsers(dataStrings[0], dataStrings[1], dataStrings[2]))
|
||||
if (! trackUsers(dataStrings[0], dataStrings[1], dataStrings[2]))
|
||||
continue;
|
||||
|
||||
// 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);
|
||||
queue.add(data); // TODO: Check and add consistency validation
|
||||
|
||||
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();
|
||||
chanList.remove(channelName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (java.io.IOException e){
|
||||
System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->run(): Internal issue in thread: caused I/O exception:\n\t"+e); // TODO: reconnect
|
||||
channels.remove(channelName);
|
||||
} catch (InterruptedException e){
|
||||
System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->run(): Interrupted\n\t"+e); // TODO: reconnect?
|
||||
}
|
||||
writerWorker.close();
|
||||
//Chanel commander thread's pipe should be closed
|
||||
chanelCommanderPipe.close();
|
||||
//Kill sub-thread
|
||||
channelCommanderThread.interrupt();
|
||||
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] THREAD "+serverName+":"+this.channelName +" ended"); // TODO:REMOVE DEBUG
|
||||
}
|
||||
|
||||
|
@ -85,39 +89,47 @@ public class ChanConsumer implements Runnable {
|
|||
case "PRIVMSG": // most common, we don't have to handle anything else
|
||||
return true;
|
||||
case "JOIN":
|
||||
addUsers(simplifyNick(initiatorArg));
|
||||
addUser(simplifyNick(initiatorArg));
|
||||
return true;
|
||||
case "PART":
|
||||
delUsers(simplifyNick(initiatorArg)); // nick non-simple
|
||||
deleteUser(simplifyNick(initiatorArg)); // nick non-simple
|
||||
return true;
|
||||
case "QUIT":
|
||||
if (userList.contains(simplifyNick(initiatorArg))) {
|
||||
delUsers(simplifyNick(initiatorArg)); // nick non-simple
|
||||
deleteUser(simplifyNick(initiatorArg)); // nick non-simple
|
||||
return true;
|
||||
} else
|
||||
}
|
||||
else
|
||||
return false; // user quit, but he/she is not in this channel
|
||||
case "KICK":
|
||||
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.replaceAll("(^.+?\\s)|(\\s.+$)", "")); // nick already simplified
|
||||
deleteUser(subjectArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")); // nick already simplified
|
||||
return true;
|
||||
case "NICK":
|
||||
if (userList.contains(simplifyNick(initiatorArg))) {
|
||||
swapUsers(simplifyNick(initiatorArg), subjectArg);
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return false; // user changed nick, but he/she is not in this channel
|
||||
}
|
||||
case "353":
|
||||
String userOnChanStr = subjectArg.substring(subjectArg.indexOf(":") + 1);
|
||||
userOnChanStr = userOnChanStr.replaceAll("[%@+]", "").trim();
|
||||
String[] usersOnChanArr = userOnChanStr.split(" ");
|
||||
userList.addAll(Arrays.asList(usersOnChanArr));
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void addUsers(String user){
|
||||
private void addUser(String user){
|
||||
if (!userList.contains(user))
|
||||
userList.add(user);
|
||||
}
|
||||
private void delUsers(String user){
|
||||
private void deleteUser(String user){
|
||||
if (user.equals(nick)) {
|
||||
endThread = true;
|
||||
}
|
||||
|
@ -129,33 +141,12 @@ public class ChanConsumer implements Runnable {
|
|||
if (userNickOld.equals(nick))
|
||||
this.nick = userNickNew;
|
||||
}
|
||||
// Create ChanelCommander
|
||||
private PrintWriter getChanelCommander(){
|
||||
PipedOutputStream streamOut = new PipedOutputStream();
|
||||
try {
|
||||
BufferedReader streamBufferedReader = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
new PipedInputStream(streamOut), StandardCharsets.UTF_8)
|
||||
);
|
||||
|
||||
ChanelCommander commander = new ChanelCommander(streamBufferedReader, serverName, channelName, configFilePath);
|
||||
|
||||
new Thread(commander).start();
|
||||
|
||||
return new PrintWriter(streamOut);
|
||||
|
||||
} catch (IOException e) {
|
||||
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:
|
||||
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.");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package InnaIrcBot.ProvidersConsumers;
|
||||
|
||||
import InnaIrcBot.Config.StorageFile;
|
||||
import InnaIrcBot.config.ConfigurationFile;
|
||||
import InnaIrcBot.IrcChannel;
|
||||
import InnaIrcBot.LogDriver.BotDriver;
|
||||
import InnaIrcBot.ReconnectControl;
|
||||
|
||||
|
@ -8,131 +9,94 @@ import java.io.*;
|
|||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
|
||||
public class DataProvider implements Runnable {
|
||||
private StorageFile configFile;
|
||||
private String serverName;
|
||||
private String userNick;
|
||||
private final ConfigurationFile configurationFile;
|
||||
private final String serverName;
|
||||
private final String nickName;
|
||||
private BufferedReader rawStreamReader;
|
||||
|
||||
private boolean ableToRun = true;
|
||||
/**
|
||||
* Initiate connection and prepare input/output streams for run()
|
||||
* */
|
||||
public DataProvider(StorageFile storageFile){
|
||||
this.configFile = storageFile;
|
||||
this.serverName = storageFile.getServerName();
|
||||
|
||||
int port = storageFile.getServerPort();
|
||||
|
||||
try {
|
||||
InetAddress inetAddress = InetAddress.getByName(serverName);
|
||||
Socket socket = new Socket(); // TODO: set timeout?
|
||||
for (int i=0; i<5; i++) {
|
||||
socket.connect(new InetSocketAddress(inetAddress, port), 5000); // 10sec = 10000
|
||||
if (socket.isConnected())
|
||||
break;
|
||||
}
|
||||
if (socket.isConnected())
|
||||
System.out.println("Socket connected");
|
||||
else {
|
||||
System.out.println("Unable to connect to remote server after 5 retry.");
|
||||
this.ableToRun = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!StreamProvider.setStream(serverName, socket)) {
|
||||
this.ableToRun = false;
|
||||
return;
|
||||
}
|
||||
InputStream inStream = socket.getInputStream();
|
||||
InputStreamReader isr = new InputStreamReader(inStream, StandardCharsets.UTF_8); //TODO set charset in options;
|
||||
this.rawStreamReader = new BufferedReader(isr);
|
||||
} catch(UnknownHostException e){
|
||||
this.ableToRun = false;
|
||||
System.out.println("Internal issue: DataProvider->constructor caused unknown host exception:\n\t"+e); // caused by InetAddress
|
||||
} catch (IOException e){
|
||||
this.ableToRun = false;
|
||||
System.out.println("Internal issue: DataProvider->constructor caused I/O exception\n\t"+e); // caused by Socket
|
||||
}
|
||||
}
|
||||
//HANDLE ALWAYS in case thread decided to die
|
||||
private void close(){
|
||||
StreamProvider.delStream(serverName);
|
||||
public DataProvider(ConfigurationFile configurationFile){
|
||||
this.configurationFile = configurationFile;
|
||||
this.serverName = configurationFile.getServerName();
|
||||
this.nickName = configurationFile.getUserNick();
|
||||
}
|
||||
|
||||
public void run(){
|
||||
if (!ableToRun || !this.initConnection(rawStreamReader)
|
||||
|| !BotDriver.setLogDriver(serverName, configFile.getLogDriver(), configFile.getLogDriverParameters(), configFile.getApplicationLogDir())) { //Prepare logDriver for using in threads.
|
||||
try {
|
||||
connect();
|
||||
} catch (Exception e){
|
||||
System.out.println("Internal issue: DataProvider->run() caused exception:\n\t"+e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
ReconnectControl.register(serverName);
|
||||
|
||||
if (! BotDriver.setLogDriver(serverName,
|
||||
configurationFile.getLogDriver(),
|
||||
configurationFile.getLogDriverParameters(),
|
||||
configurationFile.getApplicationLogDir())) { //Prepare logDriver for using in threads.)
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Used for sending data into consumers objects*/
|
||||
Map<String, PrintWriter> channelsMap = Collections.synchronizedMap(new HashMap<String, PrintWriter>());
|
||||
try {
|
||||
PipedOutputStream streamOut = new PipedOutputStream(); // K-K-K-KOMBO \m/
|
||||
Map<String, IrcChannel> ircChannels = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
BufferedReader streamBufferedReader = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
new PipedInputStream(streamOut), StandardCharsets.UTF_8)
|
||||
);
|
||||
IrcChannel systemConsumerChannel = new IrcChannel("");
|
||||
BlockingQueue<String> systemConsumerQueue = systemConsumerChannel.getChannelQueue();
|
||||
|
||||
Runnable systemConsumer = new SystemConsumer(streamBufferedReader, userNick, channelsMap, this.configFile);
|
||||
new Thread(systemConsumer).start();
|
||||
PrintWriter systemConsumerWriter = new PrintWriter(streamOut);
|
||||
Thread SystemConsumerThread = new Thread(
|
||||
new SystemConsumer(systemConsumerQueue, nickName, ircChannels, this.configurationFile));
|
||||
SystemConsumerThread.start();
|
||||
|
||||
StreamProvider.setSysConsumer(serverName, systemConsumerWriter); // Register system consumer at StreamProvider
|
||||
StreamProvider.setSysConsumer(serverName, systemConsumerQueue); // Register system consumer at StreamProvider
|
||||
|
||||
channelsMap.put("", systemConsumerWriter); // Not sure that PrintWriter is thread-safe..
|
||||
} catch (IOException e){
|
||||
System.out.println("Internal issue: DataProvider->run() I/O exception while initialized child objects.\n\t"+e); // caused by Socket
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
ircChannels.put(systemConsumerChannel.toString(), systemConsumerChannel); // Not sure that PrintWriter is thread-safe..
|
||||
////////////////////////////////////// Start loop //////////////////////////////////////////////////////////////
|
||||
StreamProvider.writeToStream(serverName,"NICK "+this.nickName);
|
||||
StreamProvider.writeToStream(serverName,"USER "+ configurationFile.getUserIdent()+" 8 * :"+ configurationFile.getUserRealName()); // TODO: Add usermode 4 rusnet
|
||||
|
||||
try {
|
||||
String rawMessage;
|
||||
String[] rawStrings; // prefix[0] command[1] command-parameters\r\n[2]
|
||||
//if there is no prefix, you should assume the message came from your client.
|
||||
String chan;
|
||||
// Say 'yes, we need reconnect if connection somehow died'
|
||||
ReconnectControl.register(serverName);
|
||||
|
||||
while ((rawMessage = rawStreamReader.readLine()) != null) {
|
||||
//System.out.println(rawMessage);
|
||||
System.out.println(rawMessage);
|
||||
if (rawMessage.startsWith(":")) {
|
||||
rawStrings = rawMessage
|
||||
.substring(1)
|
||||
.split(" :?", 3); // Removing ':'
|
||||
|
||||
|
||||
chan = rawStrings[2].replaceAll("(\\s.?$)|(\\s.+?$)", "");
|
||||
String chan = rawStrings[2].replaceAll("(\\s.?$)|(\\s.+?$)", "");
|
||||
|
||||
//System.out.println("\tChannel: "+chan+"\n\tAction: "+rawStrings[1]+"\n\tSender: "+rawStrings[0]+"\n\tMessage: "+rawStrings[2]+"\n");
|
||||
|
||||
if (rawStrings[1].equals("QUIT") || rawStrings[1].equals("NICK")) { // replace regex
|
||||
for (PrintWriter value : channelsMap.values()) {
|
||||
value.println(rawStrings[1] + " " + rawStrings[0] + " " + rawStrings[2]);
|
||||
value.flush();
|
||||
for (IrcChannel ircChannel : ircChannels.values()) {
|
||||
ircChannel.getChannelQueue().add(rawStrings[1] + " " + rawStrings[0] + " " + rawStrings[2]);
|
||||
}
|
||||
} else if (channelsMap.containsKey(chan)) {
|
||||
channelsMap.get(chan).println(rawStrings[1] + " " + rawStrings[0] + " " + rawStrings[2]);
|
||||
channelsMap.get(chan).flush();
|
||||
} else {
|
||||
channelsMap.get("").println(rawStrings[1] + " " + rawStrings[0] + " " + rawStrings[2]);
|
||||
channelsMap.get("").flush();
|
||||
}
|
||||
} else if (rawMessage.startsWith("PING :")) {
|
||||
pingSrvResponse(rawMessage);
|
||||
} else {
|
||||
else if (ircChannels.containsKey(chan)) {
|
||||
IrcChannel chnl = ircChannels.get(chan);
|
||||
chnl.getChannelQueue().add(rawStrings[1] + " " + rawStrings[0] + " " + rawStrings[2]);
|
||||
}
|
||||
else {
|
||||
systemConsumerQueue.add(rawStrings[1] + " " + rawStrings[0] + " " + rawStrings[2]);
|
||||
}
|
||||
}
|
||||
else if (rawMessage.startsWith("PING :")) {
|
||||
sendPingReply(rawMessage);
|
||||
}
|
||||
else {
|
||||
System.out.println("Not a valid response=" + rawMessage);
|
||||
}
|
||||
}
|
||||
|
@ -140,92 +104,37 @@ public class DataProvider implements Runnable {
|
|||
System.out.println("Socket issue: I/O exception"); //Connection closed. TODO: MAYBE try reconnect
|
||||
}
|
||||
finally {
|
||||
for (PrintWriter p :channelsMap.values()) {
|
||||
p.close();
|
||||
}
|
||||
this.close();
|
||||
SystemConsumerThread.interrupt();
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
private void pingSrvResponse(String rawData){
|
||||
private void connect() throws Exception{
|
||||
final int port = configurationFile.getServerPort();
|
||||
InetAddress inetAddress = InetAddress.getByName(serverName);
|
||||
Socket socket = new Socket(); // TODO: set timeout?
|
||||
for (int i = 0; i < 5; i++) {
|
||||
socket.connect(new InetSocketAddress(inetAddress, port), 5000); // 5sec
|
||||
if (socket.isConnected())
|
||||
break;
|
||||
}
|
||||
if (! socket.isConnected())
|
||||
throw new Exception("Unable to connect server.");
|
||||
|
||||
StreamProvider.setStream(serverName, socket);
|
||||
|
||||
InputStream inStream = socket.getInputStream();
|
||||
InputStreamReader isr = new InputStreamReader(inStream, StandardCharsets.UTF_8); //TODO set charset in options;
|
||||
rawStreamReader = new BufferedReader(isr);
|
||||
}
|
||||
|
||||
private void sendPingReply(String rawData){
|
||||
StreamProvider.writeToStream(serverName,"PONG :" + rawData.replace("PING :", ""));
|
||||
}
|
||||
/**
|
||||
* Initiate connection before starting main routine.
|
||||
* */
|
||||
private boolean initConnection(BufferedReader genericStreamReader){
|
||||
int nickTail = 0; // handle appendix to nickname
|
||||
|
||||
this.userNick = configFile.getUserNick();
|
||||
|
||||
if (this.userNick == null || this.userNick.isEmpty()) {
|
||||
System.out.println("Configuration issue: no nickname specified.");
|
||||
return false;
|
||||
}
|
||||
String rawMessage;
|
||||
|
||||
StreamProvider.writeToStream(serverName,"NICK "+this.userNick);
|
||||
StreamProvider.writeToStream(serverName,"USER "+configFile.getUserIdent()+" 8 * :"+configFile.getUserRealName()); // TODO: Add usermode 4 rusnet
|
||||
|
||||
try {
|
||||
// 431 ERR_NONICKNAMEGIVEN how can we get this?
|
||||
// 432 ERR_ERRONEUSNICKNAME covered
|
||||
// 433 ERR_NICKNAMEINUSE covered
|
||||
// 436 ERR_NICKCOLLISION
|
||||
// 464 ERR_PASSWDMISMATCH (password for server/znc/bnc)
|
||||
while ((rawMessage = genericStreamReader.readLine()) != null){
|
||||
System.out.println(rawMessage);
|
||||
if (rawMessage.startsWith("PING :")) {
|
||||
pingSrvResponse(rawMessage);
|
||||
}
|
||||
if (rawMessage.contains(" 001 ")) {
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
|
||||
if (!configFile.getUserMode().trim().isEmpty()){
|
||||
String modes = configFile.getUserMode();
|
||||
modes = modes.replaceAll("[\t\\s]", "");
|
||||
|
||||
for(char c :modes.toCharArray()) {
|
||||
message.append("MODE ");
|
||||
message.append(userNick);
|
||||
message.append(" +");
|
||||
message.append(c);
|
||||
message.append("\n");
|
||||
}
|
||||
}
|
||||
StreamProvider.writeToStream(serverName,message.toString());
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (rawMessage.contains(" 433 ")) {
|
||||
if (this.userNick.substring(userNick.length()-1, userNick.length()-1).equals("|"))
|
||||
this.userNick = this.userNick.substring(0,userNick.length()-1)+Integer.toString(nickTail++);
|
||||
else
|
||||
this.userNick = this.userNick+"|"+Integer.toString(nickTail++);
|
||||
|
||||
StreamProvider.writeToStream(serverName,"NICK "+this.userNick);
|
||||
}
|
||||
else if (rawMessage.contains(" 432 ")) {
|
||||
System.out.println("Configuration issue: Nickname contains unacceptable characters (432 ERR_ERRONEUSNICKNAME).");
|
||||
return false;
|
||||
}
|
||||
else if (rawMessage.contains(" 464 ")) {
|
||||
StreamProvider.writeToStream(serverName,"PASS "+configFile.getServerPass());
|
||||
}
|
||||
}
|
||||
|
||||
if (!configFile.getUserNickPass().isEmpty() && (!configFile.getUserNickAuthStyle().isEmpty() && configFile.getUserNickAuthStyle().toLowerCase().equals("freenode")))
|
||||
StreamProvider.writeToStream(serverName,"PRIVMSG NickServ :IDENTIFY "+configFile.getUserNickPass());
|
||||
else if (!configFile.getUserNickPass().isEmpty() && (!configFile.getUserNickAuthStyle().isEmpty() && configFile.getUserNickAuthStyle().toLowerCase().equals("rusnet")))
|
||||
StreamProvider.writeToStream(serverName,"NickServ IDENTIFY "+configFile.getUserNickPass());
|
||||
else if (!configFile.getUserNickPass().isEmpty())
|
||||
System.out.println("Configuration issue: Unable to determinate method of user nick identification (by password): could be \"freenode\" or \"rusnet\"\nSee \"userNickAuthStyle\".");
|
||||
|
||||
} catch (IOException e){
|
||||
System.out.println("Internal issue: DataProvider->initConnection() caused I/O exception.");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
//HANDLE ALWAYS in case thread decided to die
|
||||
private void close(){
|
||||
StreamProvider.delStream(serverName);
|
||||
ReconnectControl.notify(serverName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,46 +1,39 @@
|
|||
package InnaIrcBot.ProvidersConsumers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
public class StreamProvider {
|
||||
|
||||
private static HashMap<String, OutputStreamWriter> srvStreamMap = new HashMap<>();
|
||||
private static HashMap<String, PrintWriter> srvSysConsumersMap = new HashMap<>();
|
||||
private static final HashMap<String, OutputStreamWriter> srvStreamMap = new HashMap<>();
|
||||
private static final HashMap<String, BlockingQueue<String>> srvSysConsumersMap = new HashMap<>();
|
||||
|
||||
public static synchronized void writeToStream(String server, String message){
|
||||
try {
|
||||
srvStreamMap.get(server).write(message+"\n");
|
||||
srvStreamMap.get(server).flush();
|
||||
//System.out.println("W:"+message);
|
||||
// If this application says something, then pass it into system consumer thread to handle
|
||||
if (message.startsWith("PRIVMSG ")) {
|
||||
srvSysConsumersMap.get(server).println("INNA "+message);
|
||||
srvSysConsumersMap.get(server).flush();
|
||||
srvSysConsumersMap.get(server).add("INNA "+message);
|
||||
}
|
||||
} catch (java.io.IOException e){
|
||||
System.out.println("Internal issue: StreamProvider->writeToStream() caused I/O exception:\n\t"+e);
|
||||
} catch (IOException e){
|
||||
System.out.println("Internal issue: StreamProvider->writeToStream() caused I/O exception:\n\t"+e.getMessage());
|
||||
}
|
||||
}
|
||||
public static synchronized boolean setStream(String server, Socket socket){
|
||||
try {
|
||||
OutputStream outStream = socket.getOutputStream();
|
||||
srvStreamMap.put(server, new OutputStreamWriter(outStream));
|
||||
return true;
|
||||
} catch (java.io.IOException e){
|
||||
System.out.println("Internal issue: StreamProvider->setStream() caused I/O exception:\n\t"+e);
|
||||
return false;
|
||||
}
|
||||
public static synchronized void setStream(String server, Socket socket) throws IOException{
|
||||
OutputStream outStream = socket.getOutputStream();
|
||||
srvStreamMap.put(server, new OutputStreamWriter(outStream));
|
||||
}
|
||||
public static synchronized void delStream(String server){
|
||||
srvStreamMap.remove(server);
|
||||
srvSysConsumersMap.remove(server);
|
||||
}
|
||||
|
||||
public static synchronized void setSysConsumer(String server, PrintWriter pw){
|
||||
srvSysConsumersMap.put(server, pw);
|
||||
public static synchronized void setSysConsumer(String server, BlockingQueue<String> queue){
|
||||
srvSysConsumersMap.put(server, queue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,56 +2,45 @@ package InnaIrcBot.ProvidersConsumers;
|
|||
|
||||
import InnaIrcBot.Commanders.CTCPHelper;
|
||||
import InnaIrcBot.Commanders.PrivateMsgCommander;
|
||||
import InnaIrcBot.Config.StorageFile;
|
||||
import InnaIrcBot.ReconnectControl;
|
||||
import InnaIrcBot.config.ConfigurationFile;
|
||||
import InnaIrcBot.GlobalData;
|
||||
import InnaIrcBot.IrcChannel;
|
||||
import InnaIrcBot.LogDriver.BotDriver;
|
||||
import InnaIrcBot.LogDriver.BotSystemWorker;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
public class SystemConsumer implements Runnable{
|
||||
private BufferedReader reader;
|
||||
private final BlockingQueue<String> systemQueue;
|
||||
private BotSystemWorker writerWorker;
|
||||
private String nick;
|
||||
private String serverName;
|
||||
private Map<String, PrintWriter> channelsMap;
|
||||
private boolean proxyRequired;
|
||||
private HashMap<String, ArrayList<String>> proxyAList;
|
||||
private StorageFile storageFile;
|
||||
private final Map<String, IrcChannel> channels;
|
||||
private ConfigurationFile configurationFile;
|
||||
|
||||
private PrivateMsgCommander commander;
|
||||
|
||||
private LocalDateTime lastCTCPReplyTime;
|
||||
|
||||
SystemConsumer(BufferedReader streamReader, String userNick, Map<String, PrintWriter> map, StorageFile storage) {
|
||||
this.writerWorker = BotDriver.getSystemWorker(storage.getServerName());
|
||||
private ArrayList<Thread> channelThreads;
|
||||
private int nickTail = 0;
|
||||
|
||||
SystemConsumer(BlockingQueue<String> systemQueue, String userNick, Map<String, IrcChannel> channels, ConfigurationFile configurationFile) {
|
||||
this.systemQueue = systemQueue;
|
||||
this.writerWorker = BotDriver.getSystemWorker(configurationFile.getServerName());
|
||||
this.nick = userNick;
|
||||
this.serverName = storage.getServerName();
|
||||
this.channelsMap = map;
|
||||
this.reader = streamReader;
|
||||
|
||||
this.proxyRequired = false;
|
||||
this.proxyAList = new HashMap<>();
|
||||
this.storageFile = storage;
|
||||
|
||||
this.commander = new PrivateMsgCommander(serverName, storageFile.getBotAdministratorPassword());
|
||||
// Start pre-set channels
|
||||
StringBuilder message = new StringBuilder();
|
||||
for (String cnl : storageFile.getChannels()) { // TODO: add validation of channels.
|
||||
message.append("JOIN ");
|
||||
message.append(cnl);
|
||||
message.append("\n");
|
||||
}
|
||||
StreamProvider.writeToStream(serverName,message.toString());
|
||||
this.serverName = configurationFile.getServerName();
|
||||
this.channels = channels;
|
||||
this.channelThreads = new ArrayList<>();
|
||||
this.configurationFile = configurationFile;
|
||||
this.commander = new PrivateMsgCommander(serverName, this.configurationFile.getBotAdministratorPassword());
|
||||
|
||||
lastCTCPReplyTime = LocalDateTime.now();
|
||||
}
|
||||
|
@ -62,159 +51,115 @@ public class SystemConsumer implements Runnable{
|
|||
|
||||
setMainRoutine();
|
||||
|
||||
for (PrintWriter p :channelsMap.values()) //TODO: check, code duplication. see Data provider constructor
|
||||
p.close();
|
||||
for (Thread channel : channelThreads) { //TODO: check, code duplication. see Data provider constructor
|
||||
channel.interrupt();
|
||||
}
|
||||
|
||||
writerWorker.close();
|
||||
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] THREAD "+serverName+":[system] ended"); // TODO:REMOVE DEBUG
|
||||
}
|
||||
|
||||
private void setMainRoutine(){
|
||||
String data;
|
||||
String[] dataStrings;
|
||||
try {
|
||||
while ((data = reader.readLine()) != null) {
|
||||
dataStrings = data.split(" ",3);
|
||||
|
||||
if (proxyRequired)
|
||||
if (getProxy(dataStrings[0], dataStrings[1], dataStrings[2]))
|
||||
continue; // TODO: check this. Continue is fair?
|
||||
|
||||
if (Pattern.matches("(^[0-9]{3}$)|(^NICK$)|(^JOIN$)|(^QUIT$)|(^NOTICE$)", dataStrings[0])){
|
||||
handleNumeric(dataStrings[0], dataStrings[1], dataStrings[2]);
|
||||
}
|
||||
else if (dataStrings[0].equals("PRIVMSG")) {
|
||||
if (dataStrings[2].indexOf("\u0001") < dataStrings[2].lastIndexOf("\u0001")) {
|
||||
replyCTCP(simplifyNick(dataStrings[1]), dataStrings[2].substring(dataStrings[2].indexOf(":") + 1));
|
||||
//System.out.println("|"+dataStrings[1]+"|"+dataStrings[2].substring(dataStrings[2].indexOf(":") + 1)+"|");
|
||||
}
|
||||
else {
|
||||
commander.receiver(dataStrings[1], dataStrings[2].replaceAll("^.+?:", "").trim());
|
||||
writerWorker.logAdd("[system]", "PRIVMSG from "+dataStrings[1]+" received: ", dataStrings[2].replaceAll("^.+?:", "").trim());
|
||||
}
|
||||
}
|
||||
else if (dataStrings[0].equals("INNA")) {
|
||||
String[] splitter;
|
||||
if (dataStrings.length > 2){ // Don't touch 'cuz it's important
|
||||
splitter = dataStrings[2].split(" ", 2);
|
||||
if (splitter.length == 2){
|
||||
handleSpecial(dataStrings[1], splitter[0], splitter[1]);
|
||||
while (true) {
|
||||
String data = systemQueue.take();
|
||||
String[] dataStrings = data.split(" ",3);
|
||||
//TODO: handle mode change
|
||||
switch (dataStrings[0]){
|
||||
case "PRIVMSG":
|
||||
if (dataStrings[2].indexOf("\u0001") < dataStrings[2].lastIndexOf("\u0001")) {
|
||||
replyCTCP(simplifyNick(dataStrings[1]), dataStrings[2].substring(dataStrings[2].indexOf(":") + 1));
|
||||
}
|
||||
}
|
||||
else {
|
||||
commander.receiver(dataStrings[1], dataStrings[2].replaceAll("^.+?:", "").trim());
|
||||
writerWorker.logAdd("[system]", "PRIVMSG from "+dataStrings[1]+" received: ",
|
||||
dataStrings[2].replaceAll("^.+?:", "").trim());
|
||||
}
|
||||
break;
|
||||
case "INNA":
|
||||
String[] splitter;
|
||||
if (dataStrings.length > 2){ // Don't touch 'cuz it's important
|
||||
splitter = dataStrings[2].split(" ", 2);
|
||||
if (splitter.length == 2){
|
||||
handleSpecial(dataStrings[1], splitter[0], splitter[1]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
handleNumeric(dataStrings[0], dataStrings[1], dataStrings[2]);
|
||||
}
|
||||
else
|
||||
writerWorker.logAdd(dataStrings[0], dataStrings[1], dataStrings[2]); // TODO: Track users
|
||||
//System.out.println("System: "+"|"+dataStrings[0]+"|"+dataStrings[1]+"|"+dataStrings[2]+"|");
|
||||
}
|
||||
} catch (java.io.IOException e){
|
||||
System.out.println("Internal issue: thread SystemConsumer->run() caused I/O exception."); // TODO: reconnect OR AT LEAST DIE
|
||||
StreamProvider.writeToStream(serverName, "QUIT :Internal issue: thread ChanConsumer->run() caused I/O exception");
|
||||
}
|
||||
}
|
||||
private boolean getProxy(String eventNum, String sender, String message){ //TODO: if can't join: like channel with password
|
||||
if (eventNum.equals("353")) {
|
||||
//writerWorker.logAdd("[proxy]", "catch: "+eventNum+" from: "+sender+" :",message);
|
||||
return false; // never mind and let it flows as usual.
|
||||
catch (InterruptedException ie){
|
||||
System.out.println("Thread SystemConsumer->run() interrupted."); // TODO: reconnect OR AT LEAST DIE
|
||||
}
|
||||
else {
|
||||
//writerWorker.logAdd("[proxy]", "catch: "+eventNum+" from: "+sender+" :",message);
|
||||
String chan = message.replaceAll("(\\s.?$)|(\\s.+?$)", "");
|
||||
|
||||
if (eventNum.equals("QUIT") || eventNum.equals("NICK")) {
|
||||
for (ArrayList<String> key : proxyAList.values())
|
||||
key.add(eventNum + " " + sender + " " + message);
|
||||
return false;
|
||||
} else if (chan.equals(nick))
|
||||
return false;
|
||||
else if (proxyAList.keySet().contains(chan)) {
|
||||
proxyAList.get(chan).add(eventNum + " " + sender + " " + message);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
catch (Exception e){
|
||||
System.out.println("Internal issue: thread SystemConsumer->run(): "+e.getMessage()); // TODO: DO.. some thing
|
||||
}
|
||||
}
|
||||
|
||||
private void replyCTCP(String sender, String message){ // got simplified nick
|
||||
if (lastCTCPReplyTime.isBefore(LocalDateTime.now().minusSeconds(3))) { // TODO: Consider moving to config file. Now set to 3 sec
|
||||
lastCTCPReplyTime = LocalDateTime.now();
|
||||
if (message.equals("\u0001VERSION\u0001")) {
|
||||
private void replyCTCP(String sender, String message) { // got simplified nick
|
||||
// TODO: Consider moving to config file. Now set to 3 sec
|
||||
if (lastCTCPReplyTime.isAfter(LocalDateTime.now().minusSeconds(3)))
|
||||
return;
|
||||
|
||||
lastCTCPReplyTime = LocalDateTime.now();
|
||||
|
||||
switch (message) {
|
||||
case "\u0001VERSION\u0001":
|
||||
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001VERSION " + GlobalData.getAppVersion() + "\u0001");
|
||||
writerWorker.logAdd("[system]", "catch/handled CTCP VERSION from", sender);
|
||||
//System.out.println("NOTICE "+sender+" \u0001VERSION "+ GlobalData.getAppVersion()+"\u0001");
|
||||
} else if (message.startsWith("\u0001PING ") && message.endsWith("\u0001")) {
|
||||
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")) {
|
||||
return;
|
||||
case "\u0001CLIENTINFO\u0001":
|
||||
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO SOURCE\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")) {
|
||||
return;
|
||||
case "\u0001TIME\u0001":
|
||||
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 if (message.equals("\u0001SOURCE\u0001")) {
|
||||
return;
|
||||
case "\u0001SOURCE\u0001":
|
||||
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001SOURCE https://github.com/developersu/InnaIrcBot\u0001");
|
||||
writerWorker.logAdd("[system]", "catch/handled CTCP TIME from", sender);
|
||||
//System.out.println(":"+sender+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" \u0001SOURCE "+ ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\u0001");
|
||||
} else
|
||||
writerWorker.logAdd("[system]", "catch unknown CTCP request \"" + message + "\" from ", sender);
|
||||
return;
|
||||
}
|
||||
if (message.startsWith("\u0001PING ") && message.endsWith("\u0001")) {
|
||||
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :" + message);
|
||||
writerWorker.logAdd("[system]", "catch/handled CTCP PING from", sender);
|
||||
return;
|
||||
}
|
||||
writerWorker.logAdd("[system]", "catch unknown CTCP request \"" + message + "\" from ", sender);
|
||||
}
|
||||
|
||||
private String simplifyNick(String nick){ return nick.replaceAll("!.*$",""); }
|
||||
|
||||
private void handleSpecial(String event, String chanel, String message){
|
||||
//System.out.println("|"+event+"|"+chanel+"|"+message+"|");
|
||||
if (channelsMap.containsKey(chanel)){
|
||||
channelsMap.get(chanel).println(event+" "+nick+" "+chanel+" "+message); // WTF ><
|
||||
channelsMap.get(chanel).flush();
|
||||
//System.out.println("Formatted: |"+event+"|"+nick+"|"+chanel+" "+message+"|");
|
||||
}
|
||||
private void handleSpecial(String event, String channelName, String message){
|
||||
IrcChannel ircChannel = channels.get(channelName);
|
||||
if (ircChannel == null)
|
||||
return;
|
||||
String ircFormatterMessage = event+" "+nick+" "+channelName+" "+message;
|
||||
//System.out.println("Formatted: |"+event+"|"+nick+"|"+channelName+" "+message+"|");
|
||||
ircChannel.getChannelQueue().add(ircFormatterMessage);
|
||||
}
|
||||
//todo: nandle nickserv messages
|
||||
private void handleNumeric(String eventNum, String sender, String message){
|
||||
//todo: handle nickserv messages somehow
|
||||
private void handleNumeric(String eventNum, String sender, String message) throws Exception{
|
||||
switch (eventNum){
|
||||
case "501": // Notify user about incorrect setup
|
||||
writerWorker.logAdd("[system]", "catch/handled:", eventNum
|
||||
+ " [MODE message was sent with a nickname parameter and that the a mode flag sent was not recognized.]");
|
||||
break;
|
||||
case "433": // TODO: try to use alternative nickname
|
||||
writerWorker.logAdd("[system]", "catch/handled:", eventNum+" [nickname already in use]");
|
||||
writerWorker.logAdd("[system]", "catch/handled:", eventNum
|
||||
+ " [nickname already in use and will be changed]");
|
||||
break;
|
||||
case "353":
|
||||
writerWorker.logAdd("[system]", "catch/handled:", eventNum+" [RPL_NAMREPLY]");
|
||||
String chan = message.substring(message.indexOf(" ")+3);
|
||||
chan = chan.substring(0, chan.indexOf(" "));
|
||||
if (proxyAList.containsKey(chan)) {
|
||||
String userOnChanStr = message.substring(message.indexOf(":") + 1);
|
||||
userOnChanStr = userOnChanStr.replaceAll("[%@+]", "").trim();
|
||||
String[] usersOnChanArr = userOnChanStr.split(" ");
|
||||
String channelName = message.substring(nick.length()+3).replaceAll("\\s.*$", "");
|
||||
|
||||
PipedOutputStream streamOut = new PipedOutputStream();
|
||||
try {
|
||||
BufferedReader streamBufferedReader = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
new PipedInputStream(streamOut), StandardCharsets.UTF_8)
|
||||
);
|
||||
|
||||
channelsMap.put(chan, new PrintWriter(streamOut));
|
||||
// % @ +
|
||||
ChanConsumer consumer = new ChanConsumer(streamBufferedReader, storageFile.getServerName(), chan, nick, usersOnChanArr, storageFile.getRejoinOnKick(), channelsMap, storageFile.getChanelConfigurationsPath());
|
||||
new Thread(consumer).start();
|
||||
|
||||
for (String msgStored : proxyAList.get(chan)) {
|
||||
channelsMap.get(chan).println(msgStored);
|
||||
channelsMap.get(chan).flush();
|
||||
}
|
||||
|
||||
proxyAList.remove(chan);
|
||||
if (proxyAList.isEmpty()) {
|
||||
proxyRequired = false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.out.println("Internal issue: SystemConsumer->handleNumeric() @ JOIN: I/O exception while initialized child objects."); // caused by Socket
|
||||
return; //TODO: QA
|
||||
}
|
||||
}
|
||||
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. Log: \nEvent:|"+eventNum+"| sender:|"+sender+"| message|"+message+"|");
|
||||
IrcChannel ircChannel = channels.get(channelName);
|
||||
if (ircChannel == null)
|
||||
return;
|
||||
ircChannel.getChannelQueue().add(eventNum+" "+sender+" "+message);
|
||||
break;
|
||||
case "NICK":
|
||||
if (sender.startsWith(nick+"!")) {
|
||||
|
@ -224,9 +169,19 @@ public class SystemConsumer implements Runnable{
|
|||
break;
|
||||
case "JOIN":
|
||||
if (sender.startsWith(nick+"!")) {
|
||||
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
|
||||
IrcChannel newIrcChannel = new IrcChannel(message);
|
||||
|
||||
channels.put(message, newIrcChannel);
|
||||
// % @ +
|
||||
ChanConsumer consumer = new ChanConsumer(
|
||||
configurationFile.getServerName(),
|
||||
newIrcChannel,
|
||||
nick,
|
||||
channels);
|
||||
Thread newIrcChannelThread = new Thread(consumer);
|
||||
newIrcChannelThread.start();
|
||||
channelThreads.add(newIrcChannelThread);
|
||||
//proxyAList.get(message).add(eventNum+" "+sender+" "+message); // Add message to array linked
|
||||
writerWorker.logAdd("[system]", "joined to channel ", message);
|
||||
}
|
||||
break;
|
||||
|
@ -239,11 +194,79 @@ public class SystemConsumer implements Runnable{
|
|||
CTCPHelper.getInstance().handleCtcpReply(serverName, simplifyNick(sender), message.replaceAll("^.+?:", "").trim());
|
||||
writerWorker.logAdd("[system]", "NOTICE from "+sender+" received: ", message.replaceAll("^.+?:", "").trim());
|
||||
break;
|
||||
case "QUIT":
|
||||
case "001":
|
||||
sendUserModes();
|
||||
sendNickPassword();
|
||||
joinChannels();
|
||||
break;
|
||||
case "443":
|
||||
String newNick = nick+"|"+nickTail++;
|
||||
StreamProvider.writeToStream(serverName,"NICK "+newNick);
|
||||
break;
|
||||
case "464": // password for server/znc/bnc
|
||||
StreamProvider.writeToStream(serverName,"PASS "+configurationFile.getServerPass());
|
||||
break;
|
||||
case "432":
|
||||
System.out.println("Configuration issue: Nickname contains unacceptable characters (432 ERR_ERRONEUSNICKNAME).");
|
||||
ReconnectControl.update(serverName, false);
|
||||
|
||||
break;
|
||||
case "465":
|
||||
ReconnectControl.update(serverName, false);
|
||||
|
||||
break;
|
||||
case "QUIT": // TODO: Do something?
|
||||
break;
|
||||
default:
|
||||
writerWorker.logAdd("[system]", "catch: "+eventNum+" from: "+sender+" :",message); // TODO: QUIT comes here. Do something?
|
||||
writerWorker.logAdd("[system]", "catch: "+eventNum+" from: "+sender+" :",message);
|
||||
break;
|
||||
// 431 ERR_NONICKNAMEGIVEN how can we get this?
|
||||
// 436 ERR_NICKCOLLISION
|
||||
}
|
||||
}
|
||||
|
||||
private void sendUserModes(){
|
||||
String modes = configurationFile.getUserMode().replaceAll("[\t\\s]", "");
|
||||
|
||||
if (modes.isEmpty())
|
||||
return;
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
for(char mode : modes.toCharArray()) {
|
||||
message.append("MODE ");
|
||||
message.append(nick);
|
||||
message.append(" +");
|
||||
message.append(mode);
|
||||
message.append("\n");
|
||||
}
|
||||
|
||||
StreamProvider.writeToStream(serverName, message.toString());
|
||||
}
|
||||
|
||||
private void sendNickPassword(){
|
||||
if (configurationFile.getUserNickPass().isEmpty())
|
||||
return;
|
||||
|
||||
switch (configurationFile.getUserNickAuthStyle()){
|
||||
case "freenode":
|
||||
StreamProvider.writeToStream(serverName,"PRIVMSG NickServ :IDENTIFY "
|
||||
+ configurationFile.getUserNickPass());
|
||||
break;
|
||||
case "rusnet":
|
||||
StreamProvider.writeToStream(serverName,"NickServ IDENTIFY "
|
||||
+ configurationFile.getUserNickPass());
|
||||
}
|
||||
}
|
||||
|
||||
private void joinChannels(){
|
||||
StringBuilder joinMessage = new StringBuilder();
|
||||
|
||||
for (String cnl : configurationFile.getChannels()) { // TODO: add validation of channels.
|
||||
joinMessage.append("JOIN ");
|
||||
joinMessage.append(cnl);
|
||||
joinMessage.append("\n");
|
||||
}
|
||||
|
||||
StreamProvider.writeToStream(serverName, joinMessage.toString());
|
||||
}
|
||||
}
|
|
@ -3,21 +3,21 @@ package InnaIrcBot;
|
|||
import java.util.HashMap;
|
||||
|
||||
public class ReconnectControl {
|
||||
private static HashMap<String, Boolean> serversList = new HashMap<>();
|
||||
private static final HashMap<String, Boolean> serversList = new HashMap<>();
|
||||
public static synchronized void register(String serverName){
|
||||
serversList.put(serverName, true);
|
||||
}
|
||||
public static synchronized void update(String serverName, boolean needReconnect){
|
||||
serversList.replace(serverName, needReconnect);
|
||||
}
|
||||
public static synchronized boolean get(String serverName){ // could be null and it should be considered as false
|
||||
if (serversList.get(serverName) == null)
|
||||
return false;
|
||||
else
|
||||
return serversList.get(serverName);
|
||||
}
|
||||
public static synchronized void delete(String serverName){
|
||||
serversList.remove(serverName);
|
||||
}
|
||||
|
||||
public static synchronized void notify(String serverName) {
|
||||
if (serversList.get(serverName) == null || ! serversList.get(serverName)){
|
||||
serversList.remove(serverName);
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("DEBUG: Thread "+serverName+" removed from observable list after unexpected finish.\n\t");
|
||||
ConnectionsBuilder.getConnections().startNewConnection(serverName);
|
||||
}
|
||||
}
|
||||
|
|
79
src/main/java/InnaIrcBot/config/ConfigurationFile.java
Normal file
79
src/main/java/InnaIrcBot/config/ConfigurationFile.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
package InnaIrcBot.config;
|
||||
|
||||
public class ConfigurationFile {
|
||||
private String serverName;
|
||||
private int serverPort;
|
||||
private String serverPass;
|
||||
private String[] channels;
|
||||
private String userNick;
|
||||
private String userIdent;
|
||||
private String userRealName;
|
||||
private String userNickPass;
|
||||
private String userNickAuthStyle;
|
||||
private String userMode;
|
||||
private boolean rejoinOnKick;
|
||||
private String logDriver;
|
||||
private String[] logDriverParameters;
|
||||
private String botAdministratorPassword;
|
||||
private String chanelConfigurationsPath;
|
||||
private String applicationLogDir;
|
||||
|
||||
public ConfigurationFile(String serverName,
|
||||
int serverPort,
|
||||
String serverPass,
|
||||
String[] channels,
|
||||
String userNick,
|
||||
String userIdent,
|
||||
String userRealName,
|
||||
String userNickPass,
|
||||
String userNickAuthStyle,
|
||||
String userMode,
|
||||
boolean rejoinOnKick,
|
||||
String logDriver,
|
||||
String[] logDriverParameters,
|
||||
String botAdministratorPassword,
|
||||
String chanelConfigurationsPath,
|
||||
String applicationLogDir){
|
||||
this.serverName = serverName;
|
||||
this.serverPort = serverPort;
|
||||
this.serverPass = serverPass;
|
||||
this.channels = channels;
|
||||
this.userIdent = userIdent;
|
||||
this.userNick = userNick;
|
||||
this.userRealName = userRealName;
|
||||
this.userNickPass = userNickPass;
|
||||
this.userNickAuthStyle = userNickAuthStyle;
|
||||
this.userMode = userMode;
|
||||
this.rejoinOnKick = rejoinOnKick;
|
||||
this.logDriver = logDriver;
|
||||
this.logDriverParameters = logDriverParameters;
|
||||
this.botAdministratorPassword = botAdministratorPassword;
|
||||
this.chanelConfigurationsPath = chanelConfigurationsPath;
|
||||
this.applicationLogDir = applicationLogDir;
|
||||
}
|
||||
|
||||
public String getServerName() { return nonNullString(serverName); }
|
||||
public int getServerPort() { return serverPort; }
|
||||
public String getServerPass() { return nonNullString(serverPass); }
|
||||
public String[] getChannels() { return channels; }
|
||||
public String getUserNick() { return nonNullString(userNick); }
|
||||
public String getUserIdent() { return nonNullString(userIdent); }
|
||||
public String getUserRealName() { return nonNullString(userRealName); }
|
||||
public String getUserNickPass() { return nonNullString(userNickPass); }
|
||||
public String getUserNickAuthStyle() { return nonNullString(userNickAuthStyle); }
|
||||
public String getUserMode() { return nonNullString(userMode); }
|
||||
public boolean getRejoinOnKick() { return rejoinOnKick; }
|
||||
public String getLogDriver() { return nonNullString(logDriver); }
|
||||
public String[] getLogDriverParameters() { return logDriverParameters; }
|
||||
public String getBotAdministratorPassword() { return nonNullString(botAdministratorPassword); }
|
||||
public String getChanelConfigurationsPath() { return nonNullString(chanelConfigurationsPath); }
|
||||
public String getApplicationLogDir() { return nonNullString(applicationLogDir); }
|
||||
|
||||
public void setUserNickAuthStyle(String userNickAuthStyle) {
|
||||
this.userNickAuthStyle = userNickAuthStyle;
|
||||
}
|
||||
|
||||
private String nonNullString(String value){
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package InnaIrcBot.config;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class ConfigurationFileGenerator {
|
||||
private String fileLocation;
|
||||
|
||||
public static void generate(String fileLocation){
|
||||
new ConfigurationFileGenerator(fileLocation);
|
||||
}
|
||||
|
||||
private ConfigurationFileGenerator(String fileLocation){
|
||||
this.fileLocation = fileLocation;
|
||||
|
||||
try {
|
||||
if (locationNotDefined()) { // create new in homeDir
|
||||
setLocationDefault();
|
||||
}
|
||||
else if(locationIsFolder()) { // ends with .../ then create in dir
|
||||
setLocationInsideFolder();
|
||||
}
|
||||
|
||||
createConfigurationFile();
|
||||
|
||||
System.out.println("Configuration file created: " + this.fileLocation); // TODO: Move to l4j
|
||||
} catch (IOException e){
|
||||
System.out.println("Unable to write configuration file: \n\t"+e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void setLocationDefault(){
|
||||
fileLocation = System.getProperty("user.dir")
|
||||
+ File.separator
|
||||
+ "myBotConfig.conf";
|
||||
}
|
||||
|
||||
private boolean locationNotDefined(){
|
||||
return fileLocation == null;
|
||||
}
|
||||
|
||||
private boolean locationIsFolder(){
|
||||
return fileLocation.endsWith(File.separator) || Files.isDirectory(Paths.get(fileLocation));
|
||||
}
|
||||
|
||||
private void setLocationInsideFolder() throws IOException{
|
||||
createFoldersIfNeeded();
|
||||
if (fileLocation.endsWith(File.separator))
|
||||
fileLocation = fileLocation + "myBotConfig.conf";
|
||||
else
|
||||
fileLocation = fileLocation + File.separator + "myBotConfig.conf";
|
||||
}
|
||||
private void createFoldersIfNeeded() throws IOException{
|
||||
Path folderPath = Paths.get(fileLocation);
|
||||
if (! Files.exists(folderPath))
|
||||
Files.createDirectories(folderPath);
|
||||
}
|
||||
private void createConfigurationFile() throws IOException{
|
||||
File configurationFile = new File(this.fileLocation);
|
||||
|
||||
Writer writerFile = new OutputStreamWriter(new FileOutputStream(configurationFile.getAbsolutePath()), StandardCharsets.UTF_8);
|
||||
|
||||
ConfigurationFile configurationFileObject = new ConfigurationFile("srv",
|
||||
6667,
|
||||
"",
|
||||
new String[] {"#lpr",
|
||||
"#main"},
|
||||
"user_nick",
|
||||
"ident",
|
||||
"bot",
|
||||
"",
|
||||
"freenode",
|
||||
"ix",
|
||||
true,
|
||||
"Files",
|
||||
new String[] {System.getProperty("user.home")},
|
||||
"pswd",
|
||||
System.getProperty("user.home"),
|
||||
"/var/logs/"
|
||||
);
|
||||
|
||||
Gson writingStorageObject = new GsonBuilder().setPrettyPrinting().create();
|
||||
writingStorageObject.toJson(configurationFileObject, writerFile);
|
||||
writerFile.close();
|
||||
}
|
||||
}
|
50
src/main/java/InnaIrcBot/config/ConfigurationFileReader.java
Normal file
50
src/main/java/InnaIrcBot/config/ConfigurationFileReader.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
package InnaIrcBot.config;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class ConfigurationFileReader {
|
||||
private ConfigurationFileReader(){}
|
||||
|
||||
static ConfigurationFile read(String pathToFile) throws Exception{ // TODO: NULL or object
|
||||
ConfigurationFile storageObject;
|
||||
|
||||
File configFile = new File(pathToFile);
|
||||
|
||||
try (Reader fileReader = new InputStreamReader(new FileInputStream(configFile))) {
|
||||
storageObject = new Gson().fromJson(fileReader, ConfigurationFile.class);
|
||||
}
|
||||
|
||||
validate(storageObject);
|
||||
|
||||
return storageObject;
|
||||
}
|
||||
|
||||
private static void validate(ConfigurationFile configurationFile) throws Exception{ //TODO: more validation
|
||||
if (configurationFile.getServerName().isEmpty())
|
||||
throw new Exception("Server not defined in configuration file.");
|
||||
|
||||
if (configurationFile.getServerPort() <= 0)
|
||||
throw new Exception("Server port set incorrectly in configuration file.");
|
||||
|
||||
String nick = configurationFile.getUserNick();
|
||||
if (nick.isEmpty())
|
||||
throw new Exception("Configuration issue: no nickname specified. ");
|
||||
|
||||
if (! configurationFile.getUserNickPass().isEmpty()) {
|
||||
if (configurationFile.getUserNickAuthStyle().isEmpty())
|
||||
throw new Exception("Configuration issue: password specified while auth method is not.");
|
||||
|
||||
configurationFile.setUserNickAuthStyle( configurationFile.getUserNickAuthStyle().toLowerCase() );
|
||||
|
||||
if ( ! configurationFile.getUserNickAuthStyle().equals("rusnet") && ! configurationFile.getUserNickAuthStyle().equals("freenode"))
|
||||
throw new Exception("Configuration issue: userNickAuthStyle could be freenode or rusnet.");
|
||||
}
|
||||
|
||||
if (configurationFile.getServerPort() <= 0 || configurationFile.getServerPort() > 65535)
|
||||
throw new Exception("Server port number cannot be less/equal zero or greater then 65535");
|
||||
}
|
||||
|
||||
|
||||
}
|
22
src/main/java/InnaIrcBot/config/ConfigurationManager.java
Normal file
22
src/main/java/InnaIrcBot/config/ConfigurationManager.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
package InnaIrcBot.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigurationManager {
|
||||
private final static Map<String, ConfigurationFile> configurations = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
public static ConfigurationFile readAndSetConfiguration(String pathToConfigurationFile) throws Exception{
|
||||
ConfigurationFile configurationFile = ConfigurationFileReader.read(pathToConfigurationFile);
|
||||
configurations.put(configurationFile.getServerName(), configurationFile);
|
||||
return configurationFile;
|
||||
}
|
||||
|
||||
public static ConfigurationFile getConfiguration(String serverName) throws Exception{
|
||||
ConfigurationFile configurationFile = configurations.get(serverName);
|
||||
if (configurationFile == null)
|
||||
throw new Exception("No configuration found for server "+serverName);
|
||||
return configurationFile;
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package Temporary;
|
||||
|
||||
import InnaIrcBot.ReconnectControl;
|
||||
|
||||
public class ReconnectControlTest {
|
||||
public static void main(String[] args){
|
||||
ReconnectControl.register("testing");
|
||||
ReconnectControl.register("testing1");
|
||||
ReconnectControl.update("testing1", false);
|
||||
|
||||
System.out.println(ReconnectControl.get("testing"));
|
||||
System.out.println(ReconnectControl.get("testing1"));
|
||||
System.out.println(ReconnectControl.get("wrong"));
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package Temporary;
|
||||
|
||||
import InnaIrcBot.Config.StorageFile;
|
||||
import InnaIrcBot.config.ConfigurationFile;
|
||||
|
||||
public class StorageFileTest {
|
||||
static public void main(String[] args){
|
||||
StorageFile config = new StorageFile(
|
||||
ConfigurationFile config = new ConfigurationFile(
|
||||
"",
|
||||
0,
|
||||
"",
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package Temporary;
|
||||
|
||||
import InnaIrcBot.Config.StorageFile;
|
||||
import InnaIrcBot.Config.StorageReader;
|
||||
|
||||
public class StorageReaderTest {
|
||||
public static void main(String[] args){
|
||||
// StorageReader.readConfig("/home/loper/bot.config");
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
package Temporary;
|
||||
|
||||
import InnaIrcBot.Commanders.JoinFloodHandler;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class brokenJoinFloodHandlerTest {
|
||||
|
||||
public static void main(String[] args){
|
||||
new brokenJoinFloodHandlerTest();
|
||||
JoinFloodHandler jdh = new JoinFloodHandler(5, 5, "SRV_NAME", "#CHAN_NAME");
|
||||
System.out.println("Envents:\t5\n"
|
||||
+"Time Frame:\t5 sec\n"
|
||||
+"ServerName:\tSRV_NAME\n"
|
||||
+"Chanel:\t#CHAN_NAME\n");
|
||||
for (int i=0; i<40; i++) {
|
||||
System.out.println("Join for two users happened @"+ LocalDateTime.now());
|
||||
jdh.track("eblan");
|
||||
jdh.track("eban'ko");
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package InnaIrcBot.Commanders;
|
||||
|
||||
import InnaIrcBot.ProvidersConsumers.StreamProvider;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class JoinFloodHandlerTest {
|
||||
|
||||
private static final String serverName = "testServer";
|
||||
private static final String channelName = "testChannel";
|
||||
|
||||
private final JoinFloodHandler joinFloodHandler = new JoinFloodHandler(3, 5, serverName, channelName);
|
||||
private static final String userNickName = "John";
|
||||
private Thread socketTestThread;
|
||||
|
||||
JoinFloodHandlerTest(){
|
||||
try{
|
||||
socketTestThread = new Thread(() -> {
|
||||
try{
|
||||
ServerSocket serverSocket = new ServerSocket(60000);
|
||||
serverSocket.accept();
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
socketTestThread.start();
|
||||
|
||||
Socket testSocket = new Socket();
|
||||
testSocket.connect(new InetSocketAddress(60000));
|
||||
|
||||
StreamProvider.setStream(serverName, testSocket);
|
||||
StreamProvider.setSysConsumer(serverName, new ArrayBlockingQueue<>(100));
|
||||
}
|
||||
catch (IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@DisplayName("JoinFloodHandler: timeout 5s & limit 3 attempts")
|
||||
@Test
|
||||
void track() throws Exception{
|
||||
assertNull(joinFloodHandler.users.get(userNickName));
|
||||
|
||||
joinFloodHandler.track(userNickName);
|
||||
Thread.sleep(1000);
|
||||
joinFloodHandler.track(userNickName);
|
||||
Thread.sleep(2000);
|
||||
joinFloodHandler.track(userNickName);
|
||||
Thread.sleep(1990);
|
||||
joinFloodHandler.track(userNickName);
|
||||
|
||||
assertNull(joinFloodHandler.users.get(userNickName));
|
||||
|
||||
Thread.sleep(900);
|
||||
joinFloodHandler.track(userNickName);
|
||||
|
||||
assertTrue(joinFloodHandler.users.containsKey(userNickName));
|
||||
}
|
||||
/*
|
||||
@AfterAll
|
||||
static void cleanup(){
|
||||
socketTestThread.interrupt();
|
||||
}
|
||||
*/
|
||||
}
|
111
src/test/java/InnaIrcBot/LogDriver/BotDriverTest.java
Normal file
111
src/test/java/InnaIrcBot/LogDriver/BotDriverTest.java
Normal file
|
@ -0,0 +1,111 @@
|
|||
package InnaIrcBot.LogDriver;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
class BotDriverTest {
|
||||
@TempDir
|
||||
Path mainLogsDir,
|
||||
mainSQLiteLogsDir;
|
||||
|
||||
private static final String serverNameFiles = "irc.example.com";
|
||||
private static final String serverNameSQLite = "irc2.example.com";
|
||||
private Worker fw1;
|
||||
private Worker fw2;
|
||||
private Worker fw3;
|
||||
|
||||
@DisplayName("BotDriver: test files driver")
|
||||
@Test
|
||||
void driverFilesTest() {
|
||||
assertTrue(this::initializeFilesLogDriver);
|
||||
createWorkersForFiles();
|
||||
checkConsistency();
|
||||
checkFilesWorkers();
|
||||
validateDriver();
|
||||
checkFilesWorkers();
|
||||
close();
|
||||
}
|
||||
private void createWorkersForFiles(){
|
||||
fw1 = BotDriver.getWorker(serverNameFiles,"system");
|
||||
fw2 = BotDriver.getWorker(serverNameFiles,"#main");
|
||||
fw3 = BotDriver.getWorker(serverNameFiles,"#lpr");
|
||||
}
|
||||
|
||||
@DisplayName("BotDriver: test SQLite driver")
|
||||
@Test
|
||||
void driverSQLiteTest() {
|
||||
assertTrue(this::initializeSQLiteLogDriver);
|
||||
createWorkersForSQLite();
|
||||
checkConsistency();
|
||||
checkSQLiteWorkers();
|
||||
validateDriver();
|
||||
checkSQLiteWorkers();
|
||||
close();
|
||||
}
|
||||
private void createWorkersForSQLite(){
|
||||
fw1 = BotDriver.getWorker(serverNameSQLite,"system");
|
||||
fw2 = BotDriver.getWorker(serverNameSQLite,"#main");
|
||||
fw3 = BotDriver.getWorker(serverNameSQLite,"#lpr");
|
||||
}
|
||||
|
||||
void checkConsistency(){
|
||||
assertTrue(fw1.isConsistent());
|
||||
assertTrue(fw2.isConsistent());
|
||||
assertTrue(fw3.isConsistent());
|
||||
}
|
||||
|
||||
void checkFilesWorkers(){
|
||||
assertTrue(fw1 instanceof BotFilesWorker);
|
||||
assertTrue(fw2 instanceof BotFilesWorker);
|
||||
assertTrue(fw3 instanceof BotFilesWorker);
|
||||
}
|
||||
|
||||
void checkSQLiteWorkers(){
|
||||
assertTrue(fw1 instanceof BotSQLiteWorker);
|
||||
assertTrue(fw2 instanceof BotSQLiteWorker);
|
||||
assertTrue(fw3 instanceof BotSQLiteWorker);
|
||||
}
|
||||
|
||||
void validateDriver(){
|
||||
assertTrue(fw1.logAdd("JOIN", "de_su!loper@desktop.lan", "message1"));
|
||||
assertTrue(fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"));
|
||||
assertTrue(fw1.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"));
|
||||
assertTrue(fw1.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"));
|
||||
assertTrue(fw1.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"));
|
||||
assertTrue(fw1.logAdd("PART", "de_su!loper@desktop.lan", "#chan1"));
|
||||
|
||||
assertTrue(fw2.logAdd("JOIN", "de_su!loper@desktop.lan", "message2"));
|
||||
assertTrue(fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"));
|
||||
assertTrue(fw2.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"));
|
||||
assertTrue(fw2.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"));
|
||||
assertTrue(fw2.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"));
|
||||
assertTrue(fw2.logAdd("PART", "de_su!loper@desktop.lan", "#chan2"));
|
||||
|
||||
assertTrue(fw3.logAdd("JOIN", "de_su!loper@desktop.lan", "message3"));
|
||||
assertTrue(fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": some text here"));
|
||||
assertTrue(fw3.logAdd("PRIVMSG", "de_su!loper@desktop.lan", ": more random tests"));
|
||||
assertTrue(fw3.logAdd("NICK", "de_su!loper@desktop.lan", "developer_su"));
|
||||
assertTrue(fw3.logAdd("MODE", "de_su!loper@desktop.lan", "+b username"));
|
||||
assertTrue(fw3.logAdd("PART", "de_su!loper@desktop.lan", "#chan3"));
|
||||
}
|
||||
|
||||
private boolean initializeFilesLogDriver(){
|
||||
return BotDriver.setLogDriver(serverNameFiles, "files", new String[]{mainLogsDir.toString()}, "");
|
||||
}
|
||||
|
||||
private boolean initializeSQLiteLogDriver(){
|
||||
return BotDriver.setLogDriver(serverNameSQLite, "sqlite", new String[]{mainSQLiteLogsDir.toString()}, "");
|
||||
}
|
||||
|
||||
private void close(){
|
||||
fw1.close();
|
||||
fw2.close();
|
||||
fw3.close();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue