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 {
|
stages {
|
||||||
stage('Build') {
|
stage('Build') {
|
||||||
steps {
|
steps {
|
||||||
sh 'mvn -B -DskipTests clean package'
|
sh 'mvn package'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Test') {
|
stage('Test') {
|
||||||
steps {
|
steps {
|
||||||
echo 'Skip testing...'
|
sh 'mvn test'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Deploy') {
|
stage('Deploy') {
|
||||||
|
|
31
README.md
31
README.md
|
@ -2,12 +2,22 @@
|
||||||
|
|
||||||
Another one IRC bot in deep-deep beta.
|
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
|
## Usage
|
||||||
` -c, --configuration <name.config> [<name1.config> ...] Read Config`
|
```
|
||||||
|
-c, --configuration <name.config> [<name1.config> ...] Read Config
|
||||||
` -g, --generate [name.config] Generate Config`
|
-g, --generate [name.config] Generate Config
|
||||||
|
-v, --version Get application version
|
||||||
` -v, --version Get application version`
|
```
|
||||||
#### Configuration settings
|
#### Configuration settings
|
||||||
"userNickAuthStyle": "rusnet" or "freenode"
|
"userNickAuthStyle": "rusnet" or "freenode"
|
||||||
* rusnet - send '/nickserv IDENTIFY mySecretPass'
|
* 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.
|
* SQLite - use /yourPathSet/server.db (or /yourPathSet/yourFileName.db) sqlite file.
|
||||||
* MongoDB - write files to MongoDB. See ConfigurationExamples folder.
|
* MongoDB - write files to MongoDB. See ConfigurationExamples folder.
|
||||||
|
|
||||||
## License
|
### TODO:
|
||||||
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:
|
|
||||||
- [ ] Documentation
|
- [ ] Documentation
|
||||||
- [ ] Code refactoring
|
- [ ] Code refactoring
|
||||||
- [ ] QA: good regression testing
|
- [ ] QA: good regression testing
|
||||||
|
|
59
pom.xml
59
pom.xml
|
@ -4,13 +4,14 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>loper</groupId>
|
<groupId>loper</groupId>
|
||||||
<artifactId>InnaIrcBot</artifactId>
|
<artifactId>InnaIrcBot</artifactId>
|
||||||
<version>0.7-SNAPSHOT</version>
|
<version>0.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>InnaIrcBot</name>
|
<name>InnaIrcBot</name>
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.xerial</groupId>
|
<groupId>org.xerial</groupId>
|
||||||
|
@ -30,8 +31,45 @@
|
||||||
<version>3.9.1</version>
|
<version>3.9.1</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</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>
|
</dependencies>
|
||||||
<build><plugins>
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- ====================================================== -->
|
||||||
|
<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>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
@ -46,15 +84,25 @@
|
||||||
</excludes>
|
</excludes>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>2.4</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>default-jar</id>
|
||||||
|
<phase>none</phase>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
<version>2.5.3</version>
|
<version>3.1.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
<manifest>
|
<manifest>
|
||||||
<mainClass>
|
<mainClass>
|
||||||
InnaIrcBot.BotStart
|
InnaIrcBot.Main
|
||||||
</mainClass>
|
</mainClass>
|
||||||
</manifest>
|
</manifest>
|
||||||
</archive>
|
</archive>
|
||||||
|
@ -72,6 +120,7 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins></build>
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
</project>
|
</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;
|
package InnaIrcBot;
|
||||||
|
|
||||||
import InnaIrcBot.Config.StorageReader;
|
import InnaIrcBot.config.ConfigurationFileGenerator;
|
||||||
|
import org.apache.commons.cli.*;
|
||||||
|
|
||||||
public class BotStart {
|
public class BotStart {
|
||||||
//TODO: flood control
|
public BotStart(String[] args){
|
||||||
//TODO: setDaemon(true)
|
|
||||||
//TODO: multiple connections to one server not allowed
|
|
||||||
|
|
||||||
public static void main(String[] args){
|
final Options cliOptions = createCliOptions();
|
||||||
if (args.length != 0) {
|
CommandLineParser cliParser = new DefaultParser();
|
||||||
if (args.length >= 2) {
|
|
||||||
if (args[0].equals("--configuration") || args[0].equals("-c")) {
|
try{
|
||||||
new Connections(args);
|
CommandLine cli = cliParser.parse(cliOptions, args);
|
||||||
} else if (args[0].equals("--generate") || args[0].equals("-g")) {
|
if (cli.hasOption('v') || cli.hasOption("version")){
|
||||||
StorageReader.generateDefaultConfig(args[1]);
|
handleVersion();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cli.hasOption("c") || cli.hasOption("configuration")){
|
||||||
|
final String[] arguments = cli.getOptionValues("configuration");
|
||||||
|
for (String a: arguments)
|
||||||
|
ConnectionsBuilder.buildConnections(arguments);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cli.hasOption("g") || cli.hasOption("generate")){
|
||||||
|
final String[] arguments = cli.getOptionValues("generate");
|
||||||
|
handleGenerate(arguments);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleHelp(cliOptions);
|
||||||
|
}
|
||||||
|
catch (ParseException pe){
|
||||||
|
handleHelp(cliOptions);
|
||||||
|
}
|
||||||
|
catch (Exception e){
|
||||||
|
System.out.println("Error: ");
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (args[0].equals("--generate") || args[0].equals("-g")){
|
private Options createCliOptions(){
|
||||||
StorageReader.generateDefaultConfig(null);
|
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;
|
||||||
}
|
}
|
||||||
else if (args[0].equals("--version") || args[0].equals("-v")) {
|
|
||||||
|
private void handleVersion(){
|
||||||
System.out.println(GlobalData.getAppVersion());
|
System.out.println(GlobalData.getAppVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleHelp(Options cliOptions){
|
||||||
|
new HelpFormatter().printHelp(
|
||||||
|
120,
|
||||||
|
"InnaIrcBot.jar [OPTION]... [FILE]...",
|
||||||
|
"options:",
|
||||||
|
cliOptions,
|
||||||
|
"\n");
|
||||||
}
|
}
|
||||||
else {
|
private void handleGenerate(String[] arguments){
|
||||||
System.out.println("Usage:\n"
|
if (arguments.length > 0)
|
||||||
+" \t-c, --configuration <name.config> [<name1.config> ...]\tRead Config\n"
|
ConfigurationFileGenerator.generate(arguments[0]);
|
||||||
+"\t-g, --generate\t[name.config]\t\t\t\tGenerate Config\n"
|
else
|
||||||
+"\t-v, --version\t\t\t\t\t\tGet application version");
|
ConfigurationFileGenerator.generate(null);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,19 +12,12 @@ public class CTCPHelper {
|
||||||
private static final CTCPHelper instance = new CTCPHelper();
|
private static final CTCPHelper instance = new CTCPHelper();
|
||||||
public static CTCPHelper getInstance(){ return instance; }
|
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 server, String requesterChanelOrUser, String ctcpType, String target, String notFoundMessage){
|
||||||
|
if (!waitersQueue.containsKey(server)){ // TODO: meeeeeeeehh.. looks bad
|
||||||
void registerRequest(String requesterServer, String requesterChanelOrUser, String ctcpType, String targetObject, String notFoundMessage){
|
waitersQueue.put(server, new ArrayList<>());
|
||||||
/*
|
|
||||||
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<>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ctcpType){
|
switch (ctcpType){
|
||||||
|
@ -34,107 +27,67 @@ public class CTCPHelper {
|
||||||
case "SOURCE":
|
case "SOURCE":
|
||||||
case "TIME":
|
case "TIME":
|
||||||
case "USERINFO":
|
case "USERINFO":
|
||||||
waitersQueue.get(requesterServer).add(new CtcpRequest(requesterChanelOrUser, targetObject, notFoundMessage, ctcpType));
|
waitersQueue.get(server).add(new CTCPRequest(requesterChanelOrUser, target, notFoundMessage, ctcpType));
|
||||||
StreamProvider.writeToStream(requesterServer, "PRIVMSG "+targetObject+" :\u0001"+ctcpType+"\u0001");
|
StreamProvider.writeToStream(server, "PRIVMSG "+target+" :\u0001"+ctcpType+"\u0001");
|
||||||
break;
|
break;
|
||||||
case "PING": // TODO
|
case "PING": // TODO
|
||||||
waitersQueue.get(requesterServer).add(new CtcpRequest(requesterChanelOrUser, targetObject, notFoundMessage, ctcpType));
|
waitersQueue.get(server).add(new CTCPRequest(requesterChanelOrUser, target, notFoundMessage, ctcpType));
|
||||||
StreamProvider.writeToStream(requesterServer, "PRIVMSG "+targetObject+" :\u0001PING inna\u0001");
|
StreamProvider.writeToStream(server, "PRIVMSG "+target+" :\u0001PING inna\u0001");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleCtcpReply(String serverReplied, String whoReplied, String whatReplied){
|
public void handleCtcpReply(String serverReplied, String whoReplied, String whatReplied){
|
||||||
//System.out.println("Reply serv:|"+serverReplied+"|\nwho:|"+whoReplied+"|\nwhat:|"+whatReplied+"|");
|
|
||||||
LocalDateTime currentTime = LocalDateTime.now();
|
LocalDateTime currentTime = LocalDateTime.now();
|
||||||
if (waitersQueue.containsKey(serverReplied)){
|
|
||||||
ListIterator<CtcpRequest> iterator = waitersQueue.get(serverReplied).listIterator();
|
if (! waitersQueue.containsKey(serverReplied))
|
||||||
CtcpRequest current;
|
return;
|
||||||
String chanelOrUser;
|
|
||||||
|
ListIterator<CTCPRequest> iterator = waitersQueue.get(serverReplied).listIterator();
|
||||||
|
|
||||||
while (iterator.hasNext()){
|
while (iterator.hasNext()){
|
||||||
current = iterator.next();
|
CTCPRequest current = iterator.next();
|
||||||
if (current.isValid(currentTime)){
|
if (current.isValid(currentTime)){
|
||||||
chanelOrUser = current.getRequesterChanelOrUser(whoReplied);
|
String channelOrUser = current.getRequesterChanelOrUser(whoReplied);
|
||||||
if ( chanelOrUser != null && current.getType().equals(whatReplied.replaceAll("\\s.*$", ""))) {
|
|
||||||
|
if (channelOrUser == null || ! current.getType().equals(whatReplied.replaceAll("\\s.*$", "")))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (whatReplied.equals("PING inna"))
|
if (whatReplied.equals("PING inna"))
|
||||||
StreamProvider.writeToStream(serverReplied, "PRIVMSG " + chanelOrUser + " :" + whoReplied + ": " + Duration.between(current.getCreationTime(), currentTime).toMillis()+"ms");
|
StreamProvider.writeToStream(serverReplied, "PRIVMSG " + channelOrUser + " :" + whoReplied + ": " +
|
||||||
|
Duration.between(current.getCreationTime(), currentTime).toMillis()+"ms");
|
||||||
else
|
else
|
||||||
StreamProvider.writeToStream(serverReplied, "PRIVMSG " + chanelOrUser + " :" + whoReplied + ": " + whatReplied);
|
StreamProvider.writeToStream(serverReplied, "PRIVMSG " + channelOrUser + " :" + whoReplied + ": " + whatReplied);
|
||||||
|
}
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
//System.out.println("Drop outdated user");
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleErrorReply(String serverReplied, String whoNotFound){
|
public void handleErrorReply(String serverReplied, String whoNotFound){
|
||||||
//System.out.println("Reply serv:|"+serverReplied+"|\nwho:|"+whoNotFound+"|\n");
|
//System.out.println("Reply serv:|"+serverReplied+"|\nwho:|"+whoNotFound+"|\n");
|
||||||
LocalDateTime currentTime = LocalDateTime.now();
|
LocalDateTime currentTime = LocalDateTime.now();
|
||||||
if (waitersQueue.containsKey(serverReplied)){
|
if (! waitersQueue.containsKey(serverReplied))
|
||||||
ListIterator<CtcpRequest> iterator = waitersQueue.get(serverReplied).listIterator();
|
return;
|
||||||
CtcpRequest current;
|
|
||||||
String chanelOrUser;
|
ListIterator<CTCPRequest> iterator = waitersQueue.get(serverReplied).listIterator();
|
||||||
String notFoundMessage;
|
|
||||||
while (iterator.hasNext()){
|
while (iterator.hasNext()){
|
||||||
current = iterator.next();
|
CTCPRequest current = iterator.next();
|
||||||
if (current.isValid(currentTime)){
|
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();
|
iterator.remove();
|
||||||
}
|
String channelOrUser = current.getRequesterChanelOrUser(whoNotFound);
|
||||||
}
|
|
||||||
else{
|
if (channelOrUser == null)
|
||||||
//System.out.println("Drop outdated user: 401");
|
continue;
|
||||||
iterator.remove();
|
|
||||||
}
|
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.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
//TODO: FLOOD, JOIN FLOOD
|
//TODO: FLOOD, JOIN FLOOD
|
||||||
// TODO: @ configuration level: if in result we have empty string, no need to pass it to server
|
// TODO: @ configuration level: if in result we have empty string, no need to pass it to server
|
||||||
public class ChanelCommander implements Runnable {
|
public class ChanelCommander implements Runnable {
|
||||||
private BufferedReader reader;
|
private final BlockingQueue<String> streamQueue;
|
||||||
private String server;
|
private final String server;
|
||||||
private String chanel;
|
private final String channel;
|
||||||
//TODO: add timers
|
//TODO: add timers
|
||||||
private HashMap<String, String[]> joinMap; // 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 HashMap<String, String[]> msgMap; // 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 HashMap<String, String[]> nickMap; // 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 boolean joinFloodTrackNeed = false;
|
||||||
private JoinFloodHandler jfh;
|
private JoinFloodHandler jfh;
|
||||||
|
@ -26,10 +27,10 @@ public class ChanelCommander implements Runnable {
|
||||||
private boolean joinCloneTrackNeed = false; // todo:fix
|
private boolean joinCloneTrackNeed = false; // todo:fix
|
||||||
private JoinCloneHandler jch;
|
private JoinCloneHandler jch;
|
||||||
|
|
||||||
public ChanelCommander(BufferedReader streamReader, String serverName, String chan, String configFilePath){
|
public ChanelCommander(BlockingQueue<String> stream, String serverName, String channel, String configFilePath){
|
||||||
this.reader = streamReader;
|
this.streamQueue = stream;
|
||||||
this.server = serverName;
|
this.server = serverName;
|
||||||
this.chanel = chan;
|
this.channel = channel;
|
||||||
|
|
||||||
this.joinMap = new HashMap<>();
|
this.joinMap = new HashMap<>();
|
||||||
this.msgMap = new HashMap<>();
|
this.msgMap = new HashMap<>();
|
||||||
|
@ -39,13 +40,13 @@ public class ChanelCommander implements Runnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
System.out.println("Thread for ChanelCommander started"); // TODO:REMOVE DEBUG
|
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] ChanelCommander thread "
|
||||||
String data;
|
+server+":"+this.channel +" started");// TODO:REMOVE DEBUG
|
||||||
String[] dataStrings;
|
|
||||||
try {
|
try {
|
||||||
while ((data = reader.readLine()) != null) {
|
while (true) {
|
||||||
dataStrings = data.split(" ",3);
|
String data = streamQueue.take();
|
||||||
//event initiatorArg messageArg
|
String[] dataStrings = data.split(" ",3);
|
||||||
|
|
||||||
switch (dataStrings[0]) {
|
switch (dataStrings[0]) {
|
||||||
case "NICK":
|
case "NICK":
|
||||||
nickCame(dataStrings[2]+dataStrings[1].replaceAll("^.+?!","!"));
|
nickCame(dataStrings[2]+dataStrings[1].replaceAll("^.+?!","!"));
|
||||||
|
@ -75,8 +76,9 @@ public class ChanelCommander implements Runnable {
|
||||||
break;
|
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
|
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() ?
|
String objectToCtcp = arg1.trim().replaceAll(objectRegexp, ""); // note: trim() ?
|
||||||
if (!objectToCtcp.isEmpty()){
|
if (!objectToCtcp.isEmpty()){
|
||||||
if (CTCPType.startsWith("\\c"))
|
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
|
else
|
||||||
CTCPHelper.getInstance().registerRequest(server, simplifyNick(arg2), CTCPType.substring(2).toUpperCase(), objectToCtcp, whatToSendStringBuilder.toString());
|
CTCPHelper.getInstance().registerRequest(server, simplifyNick(arg2), CTCPType.substring(2).toUpperCase(), objectToCtcp, whatToSendStringBuilder.toString());
|
||||||
}
|
}
|
||||||
|
@ -201,40 +203,40 @@ public class ChanelCommander implements Runnable {
|
||||||
executiveStr.append(" :");
|
executiveStr.append(" :");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
executiveStr.append(chanel);
|
executiveStr.append(channel);
|
||||||
executiveStr.append(" :");
|
executiveStr.append(" :");
|
||||||
executiveStr.append(simplifyNick(who));
|
executiveStr.append(simplifyNick(who));
|
||||||
executiveStr.append(": ");
|
executiveStr.append(": ");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < messages.length; i++){
|
for (String message : messages) {
|
||||||
if ( ! messages[i].startsWith("\\"))
|
if (!message.startsWith("\\"))
|
||||||
executiveStr.append(messages[i]);
|
executiveStr.append(message);
|
||||||
else if (messages[i].equals("\\time")) // TODO: remove this shit
|
else if (message.equals("\\time")) // TODO: remove this shit
|
||||||
executiveStr.append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
executiveStr.append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||||
}
|
}
|
||||||
//System.out.println(executiveStr.toString()); //TODO: debug
|
//System.out.println(executiveStr.toString()); //TODO: debug
|
||||||
StreamProvider.writeToStream(server, executiveStr.toString());
|
StreamProvider.writeToStream(server, executiveStr.toString());
|
||||||
}
|
}
|
||||||
private void banAction(String whom){
|
private void banAction(String whom){
|
||||||
StreamProvider.writeToStream(server, "MODE "+chanel+" +b "+simplifyNick(whom)+"*!*@*");
|
StreamProvider.writeToStream(server, "MODE "+ channel +" +b "+simplifyNick(whom)+"*!*@*");
|
||||||
StreamProvider.writeToStream(server, "MODE "+chanel+" +b "+"*!*@"+whom.replaceAll("^.+@",""));
|
StreamProvider.writeToStream(server, "MODE "+ channel +" +b "+"*!*@"+whom.replaceAll("^.+@",""));
|
||||||
}
|
}
|
||||||
private void voiceAction(String whom){
|
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){
|
private void kickAction(String[] messages, String whom){
|
||||||
StringBuilder executiveStr = new StringBuilder();
|
StringBuilder executiveStr = new StringBuilder();
|
||||||
executiveStr.append("KICK ");
|
executiveStr.append("KICK ");
|
||||||
executiveStr.append(chanel);
|
executiveStr.append(channel);
|
||||||
executiveStr.append(" ");
|
executiveStr.append(" ");
|
||||||
executiveStr.append(simplifyNick(whom));
|
executiveStr.append(simplifyNick(whom));
|
||||||
executiveStr.append(" :");
|
executiveStr.append(" :");
|
||||||
|
|
||||||
for (int i = 0; i < messages.length; i++){
|
for (String message : messages) {
|
||||||
if ( ! messages[i].startsWith("\\"))
|
if (!message.startsWith("\\"))
|
||||||
executiveStr.append(messages[i]);
|
executiveStr.append(message);
|
||||||
else if (messages[i].equals("\\time"))
|
else if (message.equals("\\time"))
|
||||||
executiveStr.append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
executiveStr.append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||||
}
|
}
|
||||||
StreamProvider.writeToStream(server, executiveStr.toString());
|
StreamProvider.writeToStream(server, executiveStr.toString());
|
||||||
|
@ -256,12 +258,13 @@ public class ChanelCommander implements Runnable {
|
||||||
break;
|
break;
|
||||||
case "joinfloodcontrol":
|
case "joinfloodcontrol":
|
||||||
if (!directive[1].isEmpty() && !directive[2].isEmpty() && Pattern.matches("^[0-9]+?$", directive[1].trim()) && Pattern.matches("^[0-9]+?$", directive[2].trim())) {
|
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 events = Integer.parseInt(directive[1].trim());
|
||||||
int timeFrame = Integer.valueOf(directive[2].trim());
|
int timeFrame = Integer.parseInt(directive[2].trim());
|
||||||
if (events > 0 && timeFrame > 0) {
|
if (events > 0 && timeFrame > 0) {
|
||||||
jfh = new JoinFloodHandler(events, timeFrame, server, chanel);
|
jfh = new JoinFloodHandler(events, timeFrame, server, channel);
|
||||||
joinFloodTrackNeed = true;
|
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");
|
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;
|
break;
|
||||||
case "joinclonecontrol":
|
case "joinclonecontrol":
|
||||||
if (!directive[1].isEmpty() && !directive[2].isEmpty() && Pattern.matches("^[0-9]+?$", directive[1].trim())) {
|
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){
|
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;
|
joinCloneTrackNeed = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -289,7 +292,9 @@ public class ChanelCommander implements Runnable {
|
||||||
private void readConfing(String confFilesPath){
|
private void readConfing(String confFilesPath){
|
||||||
if (!confFilesPath.endsWith(File.separator))
|
if (!confFilesPath.endsWith(File.separator))
|
||||||
confFilesPath += 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())
|
if (!file.exists())
|
||||||
return;
|
return;
|
||||||
try {
|
try {
|
||||||
|
@ -298,10 +303,9 @@ public class ChanelCommander implements Runnable {
|
||||||
while ((line = br.readLine()) != null) {
|
while ((line = br.readLine()) != null) {
|
||||||
parse(line.split("\t"));
|
parse(line.split("\t"));
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException e) {
|
}
|
||||||
System.out.println("Internal issue: thread ChanelCommander->readConfig() can't find file:\t\n"+e);
|
catch (Exception e) {
|
||||||
} catch (IOException e){
|
System.out.println("Internal issue: thread ChanelCommander->readConfig():\t\n"+e.getMessage());
|
||||||
System.out.println("Internal issue: thread ChanelCommander->readConfig() I/O exception:\t\n"+e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,7 +22,7 @@ public class JoinCloneHandler {
|
||||||
prevUserNick = "";
|
prevUserNick = "";
|
||||||
lastCame = LocalDateTime.now().minusDays(1L);
|
lastCame = LocalDateTime.now().minusDays(1L);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
public void track(String userNick){
|
public void track(String userNick){
|
||||||
if (userNick.matches(pattern)){
|
if (userNick.matches(pattern)){
|
||||||
if (lastCame.isAfter(LocalDateTime.now().minusSeconds(timeFrameInSeconds)) && !prevUserNick.equals(userNick)){
|
if (lastCame.isAfter(LocalDateTime.now().minusSeconds(timeFrameInSeconds)) && !prevUserNick.equals(userNick)){
|
||||||
|
@ -37,8 +37,41 @@ public class JoinCloneHandler {
|
||||||
lastCame = LocalDateTime.now();
|
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){
|
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){
|
private String getNickOnly(String fullNick){
|
||||||
return fullNick.replaceAll("!.*$","");
|
return fullNick.replaceAll("!.*$","");
|
||||||
|
|
|
@ -3,58 +3,68 @@ package InnaIrcBot.Commanders;
|
||||||
import InnaIrcBot.ProvidersConsumers.StreamProvider;
|
import InnaIrcBot.ProvidersConsumers.StreamProvider;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
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;
|
|
||||||
|
|
||||||
public JoinFloodHandler(int events, int timeFrameInSeconds, String serverName, String chanelName){
|
public class JoinFloodHandler {
|
||||||
this.eventBufferSize = events;
|
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.timeFrameInSeconds = timeFrameInSeconds;
|
||||||
this.server = serverName;
|
this.server = serverName;
|
||||||
this.chanel = chanelName;
|
this.channel = channelName;
|
||||||
this.usersOnChanel = new HashMap<>();
|
this.users = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void track(String userNick){
|
public void track(String userNickname){
|
||||||
if(usersOnChanel.containsKey(userNick)){
|
if (isNewcomer(userNickname)) {
|
||||||
LocalDateTime timeOfFirstEvent = usersOnChanel.get(userNick).addLastGetFirst();
|
registerNewUser(userNickname);
|
||||||
if (timeOfFirstEvent.isAfter(LocalDateTime.now().minusSeconds(timeFrameInSeconds))) { // If first event in the queue happened after 'timeFrameSeconds ago from now'
|
return;
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
else {
|
||||||
usersOnChanel.put(userNick, new LprFIFOQueue(eventBufferSize)); // Create buffer for tracking new user joined
|
fistJoinTime = LocalDateTime.MIN;
|
||||||
usersOnChanel.get(userNick).addLastGetFirst(); // Write his/her first join time
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
return fistJoinTime;
|
||||||
|
}
|
||||||
class LprFIFOQueue {
|
private void kickBanUser(String user){
|
||||||
private int size;
|
StreamProvider.writeToStream(server,
|
||||||
private ArrayList<LocalDateTime> dateTimes;// todo stack or deque
|
"PRIVMSG "+ channel +" :"+user+": join flood ("+ joinMaxNumber +" connections in "+timeFrameInSeconds+" seconds).\n"+
|
||||||
|
"MODE "+ channel +" +b "+user+"!*@*"); // TODO: consider other ban methods
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,12 +7,12 @@ import InnaIrcBot.ReconnectControl;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class PrivateMsgCommander { // TODO: add black list: add users after failed login queries ; temporary ban
|
public class PrivateMsgCommander { // TODO: add black list: add users after failed login queries ; temporary ban
|
||||||
private String serverName;
|
private final String server;
|
||||||
private ArrayList<String> administrators;
|
private final String password;
|
||||||
private String password;
|
private final ArrayList<String> administrators;
|
||||||
|
|
||||||
public PrivateMsgCommander(String server, String adminPassword){
|
public PrivateMsgCommander(String server, String adminPassword){
|
||||||
this.serverName = server;
|
this.server = server;
|
||||||
this.administrators = new ArrayList<>();
|
this.administrators = new ArrayList<>();
|
||||||
this.password = adminPassword.trim();
|
this.password = adminPassword.trim();
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ public class PrivateMsgCommander { // T
|
||||||
case "unvoice":
|
case "unvoice":
|
||||||
if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) {
|
if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) {
|
||||||
String[] voiceArgs = cmd[1].split("(\\s)|(\t)+?", 2);
|
String[] voiceArgs = cmd[1].split("(\\s)|(\t)+?", 2);
|
||||||
unvoice(voiceArgs[0], voiceArgs[1]);
|
devoice(voiceArgs[0], voiceArgs[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tell(simplifyNick(sender), "Pattern: [-v|unvoice] <channel> <user>");
|
tell(simplifyNick(sender), "Pattern: [-v|unvoice] <channel> <user>");
|
||||||
|
@ -173,7 +173,7 @@ public class PrivateMsgCommander { // T
|
||||||
case "unhop":
|
case "unhop":
|
||||||
if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) {
|
if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) {
|
||||||
String[] hopArgs = cmd[1].split("(\\s)|(\t)+?", 2);
|
String[] hopArgs = cmd[1].split("(\\s)|(\t)+?", 2);
|
||||||
unhop(hopArgs[0], hopArgs[1]);
|
dehop(hopArgs[0], hopArgs[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tell(simplifyNick(sender), "Pattern: [-h|unhop] <channel> <user>");
|
tell(simplifyNick(sender), "Pattern: [-h|unhop] <channel> <user>");
|
||||||
|
@ -191,7 +191,7 @@ public class PrivateMsgCommander { // T
|
||||||
case "unop":
|
case "unop":
|
||||||
if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) {
|
if ((cmd.length == 2) && (cmd[1].split("(\\s)|(\t)+?",2).length == 2)) {
|
||||||
String[] args = cmd[1].split("(\\s)|(\t)+?", 2);
|
String[] args = cmd[1].split("(\\s)|(\t)+?", 2);
|
||||||
unop(args[0], args[1]);
|
deop(args[0], args[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tell(simplifyNick(sender), "Pattern: [-o|unoperator] <channel> <user>");
|
tell(simplifyNick(sender), "Pattern: [-o|unoperator] <channel> <user>");
|
||||||
|
@ -238,7 +238,7 @@ public class PrivateMsgCommander { // T
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
raw("QUIT :"+message);
|
raw("QUIT :"+message);
|
||||||
ReconnectControl.update(serverName, false);
|
ReconnectControl.update(server, false);
|
||||||
//ReconnectControl.update(serverName, true);
|
//ReconnectControl.update(serverName, true);
|
||||||
//System.exit(0); // TODO: change to normal exit
|
//System.exit(0); // TODO: change to normal exit
|
||||||
}
|
}
|
||||||
|
@ -268,7 +268,7 @@ public class PrivateMsgCommander { // T
|
||||||
raw("MODE "+object+" "+mode+" "+user);
|
raw("MODE "+object+" "+mode+" "+user);
|
||||||
}
|
}
|
||||||
private void raw(String rawText){
|
private void raw(String rawText){
|
||||||
StreamProvider.writeToStream(serverName, rawText);
|
StreamProvider.writeToStream(server, rawText);
|
||||||
}
|
}
|
||||||
private void kick(String chanel, String user, String reason){
|
private void kick(String chanel, String user, String reason){
|
||||||
if (reason == null)
|
if (reason == null)
|
||||||
|
@ -295,19 +295,19 @@ public class PrivateMsgCommander { // T
|
||||||
private void voice(String chanel, String user){
|
private void voice(String chanel, String user){
|
||||||
cmode(chanel, "+v", user);
|
cmode(chanel, "+v", user);
|
||||||
}
|
}
|
||||||
private void unvoice(String chanel, String user){
|
private void devoice(String chanel, String user){
|
||||||
cmode(chanel, "-v", user);
|
cmode(chanel, "-v", user);
|
||||||
}
|
}
|
||||||
private void hop(String chanel, String user){
|
private void hop(String chanel, String user){
|
||||||
cmode(chanel, "+h", user);
|
cmode(chanel, "+h", user);
|
||||||
}
|
}
|
||||||
private void unhop(String chanel, String user){
|
private void dehop(String chanel, String user){
|
||||||
cmode(chanel, "-h", user);
|
cmode(chanel, "-h", user);
|
||||||
}
|
}
|
||||||
private void op(String chanel, String user){
|
private void op(String chanel, String user){
|
||||||
cmode(chanel, "+o", user);
|
cmode(chanel, "+o", user);
|
||||||
}
|
}
|
||||||
private void unop(String chanel, String user){
|
private void deop(String chanel, String user){
|
||||||
cmode(chanel, "-o", user);
|
cmode(chanel, "-o", user);
|
||||||
}
|
}
|
||||||
private void topic(String channel, String topic){ raw("TOPIC "+channel+" :"+topic); }
|
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;
|
package InnaIrcBot;
|
||||||
|
|
||||||
public class GlobalData {
|
public class GlobalData {
|
||||||
private static final String version = "InnaIrcBot v0.7 \"Комсомолец\"";
|
private static final String version = "InnaIrcBot v0.8 \"Коммунарка\"";
|
||||||
public static synchronized String getAppVersion(){
|
public static synchronized String getAppVersion(){
|
||||||
return version;
|
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,15 +3,24 @@ package InnaIrcBot.LogDriver;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class BotDriver {
|
public class BotDriver {
|
||||||
private static HashMap<String, String[][]> serverDriver = new HashMap<>();
|
private final static HashMap<String, String[][]> serverDriver = new HashMap<>();
|
||||||
|
private final static HashMap<String, BotSystemWorker> systemLogWorkerMap = new HashMap<>();
|
||||||
private static HashMap<String, BotSystemWorker> systemLogWorkerMap = new HashMap<>();
|
|
||||||
/**
|
/**
|
||||||
* Define driver for desired server
|
* Define driver for desired server
|
||||||
* */
|
* */
|
||||||
// TODO: add proxy worker for using with multiple drivers
|
// TODO: add proxy worker for using with multiple drivers
|
||||||
public static synchronized boolean setLogDriver(String serverName, String driver, String[] driverParams, String applicationLogDir){
|
public static synchronized boolean setLogDriver(String serverName, String driver, String[] driverParams, String applicationLogDir){
|
||||||
if (!driver.isEmpty() && driverParams != null && driverParams.length > 0 && driverParams[0] != null && !driverParams[0].isEmpty()) {
|
if (driver == 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 = {
|
String[][] drvAndParams = {
|
||||||
{driver},
|
{driver},
|
||||||
driverParams
|
driverParams
|
||||||
|
@ -20,31 +29,30 @@ public class BotDriver {
|
||||||
systemLogWorkerMap.put(serverName, new BotSystemWorker(serverName, applicationLogDir));
|
systemLogWorkerMap.put(serverName, new BotSystemWorker(serverName, applicationLogDir));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return false;
|
public static synchronized Worker getWorker(String server, String channel){
|
||||||
}
|
if (serverDriver.containsKey(server)) {
|
||||||
public static synchronized Worker getWorker(String serverName, String chanelName){
|
switch (serverDriver.get(server)[0][0].toLowerCase()) {
|
||||||
if (serverDriver.containsKey(serverName)) {
|
|
||||||
switch (serverDriver.get(serverName)[0][0].toLowerCase()) {
|
|
||||||
case "files":
|
case "files":
|
||||||
BotFilesWorker botFilesWorker = new BotFilesWorker(serverName, serverDriver.get(serverName)[1], chanelName);
|
BotFilesWorker botFilesWorker = new BotFilesWorker(server, serverDriver.get(server)[1], channel);
|
||||||
return validateConstancy(botFilesWorker, serverName, chanelName);
|
return validateConsistancy(botFilesWorker, server, channel);
|
||||||
case "sqlite":
|
case "sqlite":
|
||||||
BotSQLiteWorker botSQLiteWorker = new BotSQLiteWorker(serverName, serverDriver.get(serverName)[1], chanelName);
|
BotSQLiteWorker botSQLiteWorker = new BotSQLiteWorker(server, serverDriver.get(server)[1], channel);
|
||||||
return validateConstancy(botSQLiteWorker, serverName, chanelName);
|
return validateConsistancy(botSQLiteWorker, server, channel);
|
||||||
case "mongodb":
|
case "mongodb":
|
||||||
BotMongoWorker botMongoWorker = new BotMongoWorker(serverName, serverDriver.get(serverName)[1], chanelName);
|
BotMongoWorker botMongoWorker = new BotMongoWorker(server, serverDriver.get(server)[1], channel);
|
||||||
return validateConstancy(botMongoWorker, serverName, chanelName);
|
return validateConsistancy(botMongoWorker, server, channel);
|
||||||
case "zero":
|
case "zero":
|
||||||
return new BotZeroWorker();
|
return new BotZeroWorker();
|
||||||
default:
|
default:
|
||||||
System.out.println("BotDriver->getWorker(): Configuration issue: can't find required driver \""
|
System.out.println("BotDriver->getWorker(): Configuration issue: can't find required driver \""
|
||||||
+serverDriver.get(serverName)[0][0]
|
+serverDriver.get(server)[0][0]
|
||||||
+"\".Using \"ZeroWorker\".");
|
+"\".Using \"ZeroWorker\".");
|
||||||
return new BotZeroWorker();
|
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();
|
return new BotZeroWorker();
|
||||||
}
|
}
|
||||||
// If channel found that it's impossible to use defined worker from user settings and asking for use ZeroWorker
|
// 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);
|
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()){
|
if (worker.isConsistent()){
|
||||||
return worker;
|
return worker;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
System.out.println("BotDriver->validateConstancy(): Unable to use "
|
System.out.println("BotDriver->validateConstancy(): Unable to use "
|
||||||
+worker.getClass().getSimpleName()+" for "+srv+"/"+chan
|
+worker.getClass().getSimpleName()+" for "+server+"/"+channel
|
||||||
+". Using ZeroWorker instead.");
|
+". Using ZeroWorker instead.");
|
||||||
return new BotZeroWorker();
|
return new BotZeroWorker();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,57 +9,63 @@ import java.time.format.DateTimeFormatter;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class BotFilesWorker implements Worker {
|
public class BotFilesWorker implements Worker {
|
||||||
|
private final String channel;
|
||||||
private String filePath;
|
private String filePath;
|
||||||
private boolean consistent = false;
|
private final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
|
||||||
private DateTimeFormatter dateFormat;
|
private LocalDate dateOnFile;
|
||||||
|
|
||||||
private LocalDate fileWriterDay;
|
|
||||||
private FileWriter fileWriter;
|
private FileWriter fileWriter;
|
||||||
|
|
||||||
private String ircServer; // hold for debug only
|
private boolean consistent;
|
||||||
|
|
||||||
public BotFilesWorker(String server, String[] driverParameters, String channel){
|
public BotFilesWorker(String server, String[] driverParameters, String channel){
|
||||||
ircServer = server;
|
this.channel = channel.replaceAll(File.separator, ",");
|
||||||
dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
|
|
||||||
|
|
||||||
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 {
|
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){
|
} catch (Exception e){
|
||||||
System.out.println("BotFilesWorker (@"+server+")->constructor(): Failure:\n\tUnable to create directory to store DB file: \n\t" +e);
|
System.out.println("BotFilesWorker (@"+server+")->constructor(): Failure:\n" + e.getMessage());
|
||||||
return; // consistent = false;
|
|
||||||
}
|
}
|
||||||
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;
|
return;
|
||||||
|
else
|
||||||
|
throw new Exception("BotFilesWorker->createServerFolder() "+filePath+" is file while directory expected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.consistent = resetFileWriter(false);
|
if (file.mkdirs())
|
||||||
|
return;
|
||||||
|
|
||||||
|
throw new Exception("BotFilesWorker->createServerFolder() Can't create directory: "+filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean resetFileWriter(boolean reassign){
|
private void resetFileWriter() throws IOException{
|
||||||
try {
|
fileWriter.close();
|
||||||
if (reassign)
|
createFileWriter();
|
||||||
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 createFileWriter() throws IOException{
|
||||||
|
dateOnFile = LocalDate.now();
|
||||||
|
File newFile = new File(filePath+channel+"_"+ dateOnFile +".txt");
|
||||||
|
fileWriter = new FileWriter(newFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConsistent() {
|
public boolean isConsistent() {
|
||||||
return consistent;
|
return consistent;
|
||||||
|
@ -70,79 +76,73 @@ public class BotFilesWorker implements Worker {
|
||||||
* argument[1] should be always 'subject'
|
* argument[1] should be always 'subject'
|
||||||
* */
|
* */
|
||||||
@Override
|
@Override
|
||||||
public boolean logAdd(String event, String initiatorArg, String messageArg) {
|
public boolean logAdd(String event, String initiator, String message) {
|
||||||
switch (event){
|
switch (event){
|
||||||
case "PRIVMSG":
|
case "PRIVMSG":
|
||||||
PRIVMSG(initiatorArg, messageArg);
|
PRIVMSG(initiator, message);
|
||||||
break;
|
break;
|
||||||
case "JOIN":
|
case "JOIN":
|
||||||
JOIN(initiatorArg, messageArg);
|
JOIN(initiator, message);
|
||||||
break;
|
break;
|
||||||
case "MODE":
|
case "MODE":
|
||||||
MODE(initiatorArg, messageArg);
|
MODE(initiator, message);
|
||||||
break;
|
break;
|
||||||
case "KICK":
|
case "KICK":
|
||||||
KICK(initiatorArg, messageArg);
|
KICK(initiator, message);
|
||||||
break;
|
break;
|
||||||
case "PART":
|
case "PART":
|
||||||
PART(initiatorArg, messageArg);
|
PART(initiator, message);
|
||||||
break;
|
break;
|
||||||
case "QUIT":
|
case "QUIT":
|
||||||
QUIT(initiatorArg, messageArg);
|
QUIT(initiator, message);
|
||||||
break;
|
break;
|
||||||
case "NICK":
|
case "NICK":
|
||||||
NICK(initiatorArg, messageArg);
|
NICK(initiator, message);
|
||||||
break;
|
break;
|
||||||
case "TOPIC":
|
case "TOPIC":
|
||||||
TOPIC(initiatorArg, messageArg);
|
TOPIC(initiator, message);
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
return consistent;
|
return consistent;
|
||||||
}
|
}
|
||||||
private void prettyPrint(String string){
|
private void prettyPrint(String string){
|
||||||
//if (consistent) { // could be not-opened
|
|
||||||
try {
|
try {
|
||||||
if (LocalDate.now().isAfter(fileWriterDay)) {
|
if (LocalDate.now().isAfter(dateOnFile)) {
|
||||||
if (!resetFileWriter(true)) {
|
resetFileWriter();
|
||||||
this.close(); // Error message already printed
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fileWriter.write(string);
|
fileWriter.write(string);
|
||||||
fileWriter.flush();
|
fileWriter.flush();
|
||||||
} catch (IOException e) {
|
} catch (Exception e){
|
||||||
System.out.println("BotFilesWorker (@" + ircServer + ")->prettyPrint() failed\n\tUnable to write logs of " + this.filePath + " because of internal failure in LocalTime representation.");
|
System.out.println("BotFilesWorker->prettyPrint() failed\n" +
|
||||||
this.close();
|
"\tUnable to write logs to " + this.filePath + " "+e.getMessage());
|
||||||
//consistent = false;
|
close();
|
||||||
} catch (NullPointerException npe){
|
|
||||||
System.out.println("BotFilesWorker (@" + ircServer + ")->prettyPrint() failed\n\tUnable to write logs of " + this.filePath + " because file descriptor already closed/was not opened.");
|
|
||||||
consistent = false;
|
consistent = false;
|
||||||
} catch (Exception unknowne){ // ??? No ideas. Just in case. Consider removing.
|
|
||||||
System.out.println("BotFilesWorker (@" + ircServer + ")->prettyPrint() failed\n\tUnable to write logs of " + this.filePath + " because of exception:\n\t"+unknowne);
|
|
||||||
this.close();
|
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
private String genDate(){
|
private String getCurrentTimestamp(){
|
||||||
return "["+LocalTime.now().format(dateFormat)+"] ";
|
return "["+LocalTime.now().format(dateFormat)+"] ";
|
||||||
}
|
}
|
||||||
private String getUserNameOnly(String userNameFull){return userNameFull.replaceAll("!.+$", "");}
|
private String getUserNameOnly(String userNameFull){
|
||||||
private String getUserNameAndHost(String userNameFull){return userNameFull.replaceAll("!.+$", "")+" [!"+userNameFull.replaceAll("^.+!", "")+"] ";}
|
return userNameFull.replaceAll("!.+$", "");
|
||||||
|
}
|
||||||
|
private String getUserNameAndHost(String userNameFull){
|
||||||
|
return userNameFull.replaceAll("!.+$", "")+" [!"+userNameFull.replaceAll("^.+!", "")+"] ";
|
||||||
|
}
|
||||||
|
|
||||||
private void PRIVMSG(String initiatorArg, String messageArg){
|
private void PRIVMSG(String initiatorArg, String messageArg){
|
||||||
String msg = messageArg.substring(messageArg.indexOf(":")+1);
|
String msg = messageArg.substring(messageArg.indexOf(":")+1);
|
||||||
if (!Pattern.matches("^\\u0001ACTION .+\\u0001", msg)){
|
|
||||||
this.prettyPrint(genDate()+"<"+getUserNameOnly(initiatorArg)+"> "+msg+"\n");
|
if (Pattern.matches("^\\u0001ACTION .+\\u0001", msg)){
|
||||||
}
|
prettyPrint(getCurrentTimestamp()+getUserNameOnly(initiatorArg)+msg.replaceAll("(^\\u0001ACTION)|(\\u0001$)","")+"\n");
|
||||||
else {
|
return;
|
||||||
this.prettyPrint(genDate()+getUserNameOnly(initiatorArg)+msg.replaceAll("(^\\u0001ACTION)|(\\u0001$)","")+"\n");
|
|
||||||
}
|
}
|
||||||
|
prettyPrint(getCurrentTimestamp()+"<"+getUserNameOnly(initiatorArg)+"> "+msg+"\n");
|
||||||
}
|
}
|
||||||
private void JOIN(String initiatorArg, String messageArg){
|
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){
|
private void MODE(String initiatorArg, String messageArg){
|
||||||
String initiatorChain;
|
String initiatorChain;
|
||||||
|
@ -150,33 +150,38 @@ public class BotFilesWorker implements Worker {
|
||||||
initiatorChain = getUserNameAndHost(initiatorArg)+"set";
|
initiatorChain = getUserNameAndHost(initiatorArg)+"set";
|
||||||
else
|
else
|
||||||
initiatorChain = initiatorArg+" set";
|
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){
|
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");
|
" kicked by "+getUserNameAndHost(initiatorArg)+"with reason: "+messageArg.replaceAll("^.+?:", "")+"\n");
|
||||||
}
|
}
|
||||||
private void PART(String initiatorArg, String messageArg){
|
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){
|
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){
|
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) {
|
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
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
if (fileWriter !=null)
|
|
||||||
fileWriter.close();
|
fileWriter.close();
|
||||||
}
|
}
|
||||||
catch (java.io.IOException e){
|
catch (NullPointerException ignore) {}
|
||||||
System.out.println("BotFilesWorker (@"+ircServer+")->close() failed\n\tUnable to properly close file: "+this.filePath); // Live with it.
|
catch (IOException e){
|
||||||
|
System.out.println("BotFilesWorker->close() failed\n" +
|
||||||
|
"\tUnable to properly close file: "+this.filePath); // Live with it.
|
||||||
}
|
}
|
||||||
this.consistent = false;
|
this.consistent = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,23 +18,27 @@ import java.util.concurrent.TimeUnit;
|
||||||
* 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.
|
* 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.
|
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 static Map<String, MongoClient> serversMap = Collections.synchronizedMap(new HashMap<String, MongoClient>());
|
private final String server;
|
||||||
|
|
||||||
private String ircServer;
|
|
||||||
private MongoCollection<Document> collection;
|
private MongoCollection<Document> collection;
|
||||||
private boolean consistent = false;
|
private boolean consistent;
|
||||||
|
|
||||||
public BotMongoWorker(String ircServer, String[] driverParameters, String channel){
|
public BotMongoWorker(String server, String[] driverParameters, String channel){
|
||||||
this.ircServer = ircServer;
|
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 mongoUser;
|
||||||
String mongoPass;
|
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()) {
|
if (driverParameters.length == 4 && !driverParameters[2].isEmpty() && !driverParameters[3].isEmpty()) {
|
||||||
mongoUser = driverParameters[2];
|
mongoUser = driverParameters[2];
|
||||||
mongoPass = driverParameters[3];
|
mongoPass = driverParameters[3];
|
||||||
|
@ -43,47 +47,44 @@ public class BotMongoWorker implements Worker { //TODO consi
|
||||||
mongoUser = "anon";
|
mongoUser = "anon";
|
||||||
mongoPass = "anon";
|
mongoPass = "anon";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
return; // consistent = false
|
|
||||||
|
|
||||||
if (!serversMap.containsKey(ircServer)){
|
if (! serversMap.containsKey(server)){
|
||||||
/* // Leave this validations for better times.
|
/* // Leave this validations for better times.
|
||||||
CommandListener mongoCommandListener = new CommandListener() {
|
CommandListener mongoCommandListener = new CommandListener() {
|
||||||
@Override
|
@Override
|
||||||
public void commandStarted(CommandStartedEvent commandStartedEvent) {
|
public void commandStarted(CommandStartedEvent commandStartedEvent) {
|
||||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandStarted");
|
System.out.println("BotMongoWorker (@"+this.server+"): C: commandStarted");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void commandSucceeded(CommandSucceededEvent commandSucceededEvent) {
|
public void commandSucceeded(CommandSucceededEvent commandSucceededEvent) {
|
||||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandSucceeded");
|
System.out.println("BotMongoWorker (@"+this.server+"): C: commandSucceeded");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void commandFailed(CommandFailedEvent commandFailedEvent) {
|
public void commandFailed(CommandFailedEvent commandFailedEvent) {
|
||||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): C: commandFailed");
|
System.out.println("BotMongoWorker (@"+this.server+"): C: commandFailed");
|
||||||
//consistent = false;
|
//consistent = false;
|
||||||
//close(ircServer); // ircServer recieved by constructor, not this.ircServer
|
//close(server); // server recieved by constructor, not this.server
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
ServerListener mongoServerListener = new ServerListener() {
|
ServerListener mongoServerListener = new ServerListener() {
|
||||||
@Override
|
@Override
|
||||||
public void serverOpening(ServerOpeningEvent serverOpeningEvent) {
|
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
|
@Override
|
||||||
public void serverClosed(ServerClosedEvent serverClosedEvent) {
|
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
|
@Override
|
||||||
public void serverDescriptionChanged(ServerDescriptionChangedEvent serverDescriptionChangedEvent) {
|
public void serverDescriptionChanged(ServerDescriptionChangedEvent serverDescriptionChangedEvent) {
|
||||||
if (!serverDescriptionChangedEvent.getNewDescription().isOk()) {
|
if (!serverDescriptionChangedEvent.getNewDescription().isOk()) {
|
||||||
close(ircServer); // ircServer recieved by constructor, not this.ircServer
|
close(server); // server recieved by constructor, not this.server
|
||||||
System.out.println("BotMongoWorker (@"+ircServer+"): ServerListener: Server description changed (exception occurs): "
|
System.out.println("BotMongoWorker (@"+server+"): ServerListener: Server description changed (exception occurs): "
|
||||||
+ serverDescriptionChangedEvent.getNewDescription().getException());
|
+ serverDescriptionChangedEvent.getNewDescription().getException());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,111 +92,98 @@ public class BotMongoWorker implements Worker { //TODO consi
|
||||||
|
|
||||||
MongoClientSettings MCS = MongoClientSettings.builder()
|
MongoClientSettings MCS = MongoClientSettings.builder()
|
||||||
// .addCommandListener(mongoCommandListener)
|
// .addCommandListener(mongoCommandListener)
|
||||||
.applyConnectionString(new ConnectionString("mongodb://"+mongoHostAddr))
|
.applyConnectionString(new ConnectionString("mongodb://"+mongoHostAddress))
|
||||||
.applyToClusterSettings(builder -> builder.serverSelectionTimeout(5, TimeUnit.SECONDS))
|
.applyToClusterSettings(builder -> builder.serverSelectionTimeout(5, TimeUnit.SECONDS))
|
||||||
.applyToServerSettings(builder -> builder.addServerListener(mongoServerListener))
|
.applyToServerSettings(builder -> builder.addServerListener(mongoServerListener))
|
||||||
.credential(MongoCredential.createCredential(mongoUser, mongoDBName, mongoPass.toCharArray()))
|
.credential(MongoCredential.createCredential(mongoUser, mongoDBName, mongoPass.toCharArray()))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MongoClient mongoClient = MongoClients.create(MCS);
|
MongoClient mongoClient = MongoClients.create(MCS);
|
||||||
serversMap.put(ircServer, mongoClient);
|
serversMap.put(server, mongoClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
MongoDatabase mongoDB = serversMap.get(ircServer).getDatabase(mongoDBName);
|
MongoDatabase mongoDB = serversMap.get(server).getDatabase(mongoDBName);
|
||||||
collection = mongoDB.getCollection(ircServer + channel);
|
collection = mongoDB.getCollection(server + channel);
|
||||||
|
|
||||||
Document ping = new Document("ping", 1);
|
Document ping = new Document("ping", 1);
|
||||||
//
|
//
|
||||||
try {
|
try {
|
||||||
Document answer = mongoDB.runCommand(ping); // reports to monitor thread if some fuckups happens
|
Document answer = mongoDB.runCommand(ping); // reports to monitor thread if some fuckups happens
|
||||||
if (answer.get("ok") == null || (Double)answer.get("ok") != 1.0d){
|
if (answer.get("ok") == null || (Double)answer.get("ok") != 1.0d){
|
||||||
close(ircServer);
|
close(server);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
consistent = true;
|
consistent = true;
|
||||||
} catch (MongoCommandException mce){
|
} catch (MongoCommandException mce){
|
||||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): Command exception. Check if username/password set correctly.");
|
System.out.println("BotMongoWorker (@"+this.server +"): Command exception. Check if username/password set correctly.");
|
||||||
close(ircServer); // ircServer received by constructor, not this.ircServer
|
close(server); // server received by constructor, not this.server
|
||||||
} catch (MongoTimeoutException mte) {
|
} catch (MongoTimeoutException mte) {
|
||||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): Timeout exception.");
|
System.out.println("BotMongoWorker (@"+this.server +"): Timeout exception.");
|
||||||
close(ircServer); // ircServer received by constructor, not this.ircServer
|
close(server); // server received by constructor, not this.server
|
||||||
}catch (MongoException me){
|
}catch (MongoException me){
|
||||||
System.out.println("BotMongoWorker (@"+this.ircServer+"): MongoDB Exception.");
|
System.out.println("BotMongoWorker (@"+this.server +"): MongoDB Exception.");
|
||||||
close(ircServer); // ircServer received by constructor, not this.ircServer
|
close(server); // server received by constructor, not this.server
|
||||||
} catch (IllegalStateException ise){
|
} 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;
|
consistent = false;
|
||||||
// no need to close() obviously
|
// no need to close() obviously
|
||||||
}
|
}
|
||||||
|
|
||||||
if (consistent){
|
if (consistent){
|
||||||
ThingToCloseOnDie thing = new ThingToCloseOnDie() {
|
ThingToCloseOnDie thing = () -> {
|
||||||
@Override
|
if (serversMap.containsKey(server)) {
|
||||||
public void die() {
|
serversMap.get(server).close();
|
||||||
if (serversMap.containsKey(ircServer)) {
|
serversMap.remove(server);
|
||||||
try {
|
|
||||||
serversMap.get(ircServer).close();
|
|
||||||
serversMap.remove(ircServer);
|
|
||||||
}catch (Exception e){
|
|
||||||
System.out.println("ThingToCloseOnDie: something went wrong when tried to close MongoDB connection\t\n"+e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BotDriver.getSystemWorker(ircServer).registerInSystemWorker(thing);
|
BotDriver.getSystemWorker(server).registerInSystemWorker(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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())
|
Document document = new Document("date", getDate())
|
||||||
.append("event", event)
|
.append("event", event)
|
||||||
.append("initiator", initiatorArg);
|
.append("initiator", initiator);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case "NICK":
|
|
||||||
case "JOIN":
|
|
||||||
document.append("message1", messageArg);
|
|
||||||
//preparedStatement.setString(5, null);
|
|
||||||
break;
|
|
||||||
case "PART":
|
case "PART":
|
||||||
case "QUIT":
|
case "QUIT":
|
||||||
case "TOPIC":
|
case "TOPIC":
|
||||||
document.append("message1", messageArg.replaceAll("^.+?:", ""));
|
document.append("message1", message.replaceAll("^.+?:", ""));
|
||||||
//preparedStatement.setString(5, null);
|
|
||||||
break;
|
break;
|
||||||
case "MODE":
|
case "MODE":
|
||||||
document.append("message1", messageArg.replaceAll("(^(.+?\\s){1})|(\\s.+$)",""));
|
document.append("message1", message.replaceAll("(^(.+?\\s){1})|(\\s.+$)",""));
|
||||||
document.append("message2", messageArg.replaceAll("^(.+?\\s){2}", ""));
|
document.append("message2", message.replaceAll("^(.+?\\s){2}", ""));
|
||||||
break;
|
break;
|
||||||
case "KICK":
|
case "KICK":
|
||||||
document.append("message1", messageArg.replaceAll("^.+?:", ""));
|
document.append("message1", message.replaceAll("^.+?:", ""));
|
||||||
document.append("message2", messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", ""));
|
document.append("message2", message.replaceAll("(^.+?\\s)|(\\s.+$)", ""));
|
||||||
break;
|
break;
|
||||||
case "PRIVMSG":
|
case "PRIVMSG":
|
||||||
document.append("message1", messageArg.replaceAll("^:", ""));
|
document.append("message1", message.replaceAll("^:", ""));
|
||||||
//preparedStatement.setString(5,null);
|
|
||||||
break;
|
break;
|
||||||
|
case "NICK":
|
||||||
|
case "JOIN":
|
||||||
default:
|
default:
|
||||||
document.append("message1", messageArg);
|
document.append("message1", message);
|
||||||
//preparedStatement.setString(5,null);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
collection.insertOne(document); // TODO: call finalize?
|
collection.insertOne(document); // TODO: call finalize?
|
||||||
consistent = true; // if no exceptions, then true
|
consistent = true; // if no exceptions, then true
|
||||||
} catch (MongoCommandException mce){
|
} 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();
|
this.close();
|
||||||
} catch (MongoTimeoutException mte) {
|
} catch (MongoTimeoutException mte) {
|
||||||
System.out.println("BotMongoWorker (@"+this.ircServer+")->logAdd(): Timeout exception.");
|
System.out.println("BotMongoWorker (@"+this.server +")->logAdd(): Timeout exception.");
|
||||||
this.close();
|
this.close();
|
||||||
}catch (MongoException me){
|
}catch (MongoException me){
|
||||||
System.out.println("BotMongoWorker (@"+this.ircServer+")->logAdd(): MongoDB Exception.");
|
System.out.println("BotMongoWorker (@"+this.server +")->logAdd(): MongoDB Exception.");
|
||||||
this.close();
|
this.close();
|
||||||
} catch (IllegalStateException ise){
|
} 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();
|
this.close();
|
||||||
}
|
}
|
||||||
return consistent;
|
return consistent;
|
||||||
|
@ -214,7 +202,7 @@ public class BotMongoWorker implements Worker { //TODO consi
|
||||||
if (serversMap.containsKey(server)) {
|
if (serversMap.containsKey(server)) {
|
||||||
serversMap.get(server).close();
|
serversMap.get(server).close();
|
||||||
serversMap.remove(server);
|
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;
|
consistent = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,37 +155,37 @@ public class BotSQLiteWorker implements Worker {
|
||||||
public boolean isConsistent() {return consistent; }
|
public boolean isConsistent() {return consistent; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean logAdd(String event, String initiatorArg, String messageArg) {
|
public boolean logAdd(String event, String initiator, String message) {
|
||||||
try {
|
try {
|
||||||
preparedStatement.setLong(1, getDate());
|
preparedStatement.setLong(1, getDate());
|
||||||
preparedStatement.setString(2, event);
|
preparedStatement.setString(2, event);
|
||||||
preparedStatement.setString(3, initiatorArg);
|
preparedStatement.setString(3, initiator);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case "NICK":
|
case "NICK":
|
||||||
case "JOIN":
|
case "JOIN":
|
||||||
preparedStatement.setString(4, messageArg);
|
preparedStatement.setString(4, message);
|
||||||
preparedStatement.setString(5, null);
|
preparedStatement.setString(5, null);
|
||||||
break;
|
break;
|
||||||
case "PART":
|
case "PART":
|
||||||
case "QUIT":
|
case "QUIT":
|
||||||
case "TOPIC":
|
case "TOPIC":
|
||||||
preparedStatement.setString(4, messageArg.replaceAll("^.+?:", ""));
|
preparedStatement.setString(4, message.replaceAll("^.+?:", ""));
|
||||||
preparedStatement.setString(5, null);
|
preparedStatement.setString(5, null);
|
||||||
break;
|
break;
|
||||||
case "MODE":
|
case "MODE":
|
||||||
preparedStatement.setString(4, messageArg.replaceAll("(^(.+?\\s){1})|(\\s.+$)",""));
|
preparedStatement.setString(4, message.replaceAll("(^(.+?\\s){1})|(\\s.+$)",""));
|
||||||
preparedStatement.setString(5, messageArg.replaceAll("^(.+?\\s){2}", ""));
|
preparedStatement.setString(5, message.replaceAll("^(.+?\\s){2}", ""));
|
||||||
break;
|
break;
|
||||||
case "KICK":
|
case "KICK":
|
||||||
preparedStatement.setString(4, messageArg.replaceAll("^.+?:", ""));
|
preparedStatement.setString(4, message.replaceAll("^.+?:", ""));
|
||||||
preparedStatement.setString(5, messageArg.replaceAll("(^.+?\\s)|(\\s.+$)", ""));
|
preparedStatement.setString(5, message.replaceAll("(^.+?\\s)|(\\s.+$)", ""));
|
||||||
break;
|
break;
|
||||||
case "PRIVMSG":
|
case "PRIVMSG":
|
||||||
preparedStatement.setString(4, messageArg.replaceAll("^:", ""));
|
preparedStatement.setString(4, message.replaceAll("^:", ""));
|
||||||
preparedStatement.setString(5,null);
|
preparedStatement.setString(5,null);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
preparedStatement.setString(4, messageArg);
|
preparedStatement.setString(4, message);
|
||||||
preparedStatement.setString(5,null);
|
preparedStatement.setString(5,null);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,48 +9,43 @@ import java.time.format.DateTimeFormatter;
|
||||||
public class BotSystemWorker implements SystemWorker{
|
public class BotSystemWorker implements SystemWorker{
|
||||||
|
|
||||||
private FileWriter fileWriter;
|
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.
|
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;
|
private boolean consistent = false;
|
||||||
|
|
||||||
public BotSystemWorker(String ircServer, String appLogDir){
|
public BotSystemWorker(String server, String appLogDir){
|
||||||
this.ircServer = ircServer;
|
this.server = server;
|
||||||
this.dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
|
|
||||||
|
|
||||||
|
|
||||||
if (appLogDir.isEmpty()) {
|
if (appLogDir.isEmpty()) {
|
||||||
if (System.getProperty("os.name").toLowerCase().startsWith("win")) {
|
appLogDir = System.getProperty("java.io.tmpdir")+File.separator+"innaircbot"+File.separator;
|
||||||
appLogDir = System.getProperty("user.home")+ File.separator
|
|
||||||
+"AppData"+File.separator
|
|
||||||
+"Local"+File.separator
|
|
||||||
+"InnaIrcBot"+File.separator;
|
|
||||||
} else {
|
|
||||||
appLogDir = "/var/log/innaircbot/";
|
|
||||||
}
|
}
|
||||||
|
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);
|
File logFile = new File(appLogDir);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logFile.getParentFile().mkdirs();
|
if (! logFile.getParentFile().exists()) {
|
||||||
} catch (SecurityException e){
|
if (! logFile.getParentFile().mkdirs()){
|
||||||
System.out.println("BotSystemWorker (@"+ircServer+")->constructor() failed. Unable to create sub-directory(-ies) to store logs file ("+appLogDir+"):\n\t"+e);
|
System.out.println("BotSystemWorker (@"+server+")->constructor() failed:\n" +
|
||||||
return; // Consistent = false
|
"\tUnable to create sub-directory(-ies) to store log file: " + appLogDir);
|
||||||
}
|
|
||||||
if (!logFile.getParentFile().exists()) {
|
|
||||||
System.out.println("BotSystemWorker (@"+ircServer+")->constructor() failed:\n\tUnable to create sub-directory(-ies) to store log file: " + appLogDir);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
}
|
||||||
this.fileWriter = new FileWriter(logFile, true);
|
fileWriter = new FileWriter(logFile, true);
|
||||||
consistent = 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){
|
} 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,23 +59,15 @@ public class BotSystemWorker implements SystemWorker{
|
||||||
try {
|
try {
|
||||||
fileWriter.write(genDate() + event + " " + initiatorArg + " " + messageArg + "\n");
|
fileWriter.write(genDate() + event + " " + initiatorArg + " " + messageArg + "\n");
|
||||||
fileWriter.flush();
|
fileWriter.flush();
|
||||||
} catch (IOException e) {
|
} catch (Exception e) { // ??? No ideas. Just in case. Consider removing.
|
||||||
System.out.println("BotSystemWorker (@" + ircServer + ")->logAdd() failed\n\tUnable to write logs of because of internal failure in LocalTime representation.");
|
System.out.println("BotSystemWorker (@" + server + ")->logAdd() failed\n\tUnable to write logs of because of exception:\n\t" + e.getMessage());
|
||||||
//this.close();
|
|
||||||
consistent = false;
|
|
||||||
} catch (NullPointerException npe) {
|
|
||||||
System.out.println("BotSystemWorker (@" + ircServer + ")->logAdd() failed\n\tUnable to write logs of because file descriptor already closed/was not opened.");
|
|
||||||
consistent = false;
|
|
||||||
} catch (Exception unknowne) { // ??? No ideas. Just in case. Consider removing.
|
|
||||||
System.out.println("BotSystemWorker (@" + ircServer + ")->logAdd() failed\n\tUnable to write logs of because of exception:\n\t" + unknowne);
|
|
||||||
//this.close();
|
//this.close();
|
||||||
consistent = false;
|
consistent = false;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
System.out.println(genDate() + event + " " + initiatorArg + " " + messageArg + "\n");
|
System.out.println(genDate() + event + " " + initiatorArg + " " + messageArg + "\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerInSystemWorker(ThingToCloseOnDie thing){
|
public void registerInSystemWorker(ThingToCloseOnDie thing){
|
||||||
|
@ -93,14 +80,11 @@ public class BotSystemWorker implements SystemWorker{
|
||||||
public void close() {
|
public void close() {
|
||||||
if (thingToCloseOnDie != null)
|
if (thingToCloseOnDie != null)
|
||||||
thingToCloseOnDie.die();
|
thingToCloseOnDie.die();
|
||||||
if (fileWriter != null) {
|
|
||||||
try {
|
try {
|
||||||
fileWriter.close();
|
fileWriter.close();
|
||||||
}
|
}
|
||||||
catch (java.io.IOException e){
|
catch (IOException | NullPointerException ignore){}
|
||||||
System.out.println("BotSystemWorker (@"+ircServer+")->close() failed\n\tUnable to properly close logs file."); // Live with it.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
consistent = false;
|
consistent = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ public class BotZeroWorker implements Worker{
|
||||||
public boolean isConsistent() {return true;}
|
public boolean isConsistent() {return true;}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean logAdd(String event, String initiatorArg, String messageArg) { return true; }
|
public boolean logAdd(String event, String initiator, String message) { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {}
|
public void close() {}
|
||||||
|
|
|
@ -6,8 +6,8 @@ public interface Worker {
|
||||||
boolean isConsistent();
|
boolean isConsistent();
|
||||||
|
|
||||||
boolean logAdd(String event,
|
boolean logAdd(String event,
|
||||||
String initiatorArg,
|
String initiator,
|
||||||
String messageArg);
|
String message);
|
||||||
|
|
||||||
void close();
|
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;
|
package InnaIrcBot.ProvidersConsumers;
|
||||||
|
|
||||||
import InnaIrcBot.Commanders.ChanelCommander;
|
import InnaIrcBot.Commanders.ChanelCommander;
|
||||||
|
import InnaIrcBot.GlobalData;
|
||||||
|
import InnaIrcBot.IrcChannel;
|
||||||
import InnaIrcBot.LogDriver.BotDriver;
|
import InnaIrcBot.LogDriver.BotDriver;
|
||||||
import InnaIrcBot.LogDriver.Worker;
|
import InnaIrcBot.LogDriver.Worker;
|
||||||
|
import InnaIrcBot.config.ConfigurationManager;
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
|
||||||
|
|
||||||
public class ChanConsumer implements Runnable {
|
public class ChanConsumer implements Runnable {
|
||||||
private BufferedReader reader;
|
private final BlockingQueue<String> chanConsumerQueue;
|
||||||
private String serverName;
|
private final String serverName;
|
||||||
private String channelName;
|
private final String channelName;
|
||||||
private Worker writerWorker;
|
private Worker writerWorker;
|
||||||
private ArrayList<String> userList;
|
private ArrayList<String> userList;
|
||||||
private String nick;
|
private String nick;
|
||||||
private boolean rejoin;
|
private final boolean rejoin;
|
||||||
private Map<String, PrintWriter> chanList;
|
private final Map<String, IrcChannel> channels;
|
||||||
private String configFilePath;
|
|
||||||
|
|
||||||
private PrintWriter chanelCommanderPipe;
|
private Thread channelCommanderThread;
|
||||||
|
private BlockingQueue<String> queue;
|
||||||
|
|
||||||
private boolean endThread = false;
|
private boolean endThread = false;
|
||||||
|
|
||||||
ChanConsumer(BufferedReader streamReader, String serverName, String channelName, String ownNick, String[] usersOnChan, boolean rejoinAlways, Map<String, PrintWriter> map, String configFilePath){
|
ChanConsumer(String serverName,
|
||||||
this.reader = streamReader;
|
IrcChannel thisIrcChannel,
|
||||||
|
String ownNick,
|
||||||
|
Map<String, IrcChannel> channels) throws Exception{
|
||||||
|
this.chanConsumerQueue = thisIrcChannel.getChannelQueue();
|
||||||
this.serverName = serverName;
|
this.serverName = serverName;
|
||||||
this.channelName = channelName;
|
this.channelName = thisIrcChannel.toString();
|
||||||
this.writerWorker = BotDriver.getWorker(serverName, channelName);
|
this.writerWorker = BotDriver.getWorker(serverName, channelName);
|
||||||
this.userList = new ArrayList<>();
|
this.userList = new ArrayList<>();
|
||||||
this.userList.addAll(Arrays.asList(usersOnChan));
|
|
||||||
this.nick = ownNick;
|
this.nick = ownNick;
|
||||||
this.rejoin = rejoinAlways;
|
this.rejoin = ConfigurationManager.getConfiguration(serverName).getRejoinOnKick();
|
||||||
this.chanList = map;
|
this.channels = channels;
|
||||||
this.configFilePath = configFilePath;
|
|
||||||
// Create chanel commander thread, get pipe
|
// 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(){
|
public void run(){
|
||||||
String data;
|
String data;
|
||||||
String[] dataStrings;
|
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 {
|
try {
|
||||||
while ((data = reader.readLine()) != null) {
|
while (! endThread) {
|
||||||
|
data = chanConsumerQueue.take();
|
||||||
dataStrings = data.split(" ",3);
|
dataStrings = data.split(" ",3);
|
||||||
|
|
||||||
if (!trackUsers(dataStrings[0], dataStrings[1], dataStrings[2]))
|
if (! trackUsers(dataStrings[0], dataStrings[1], dataStrings[2]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Send to chanel commander thread
|
// Send to chanel commander thread
|
||||||
chanelCommanderPipe.println(data);
|
queue.add(data); // TODO: Check and add consistency validation
|
||||||
chanelCommanderPipe.flush();
|
|
||||||
//System.out.println("|"+dataStrings[0]+"|"+dataStrings[1]+"|"+dataStrings[2]+"|");
|
|
||||||
//System.out.println("Thread: "+this.channelName +"\n\tArray:"+ userList);
|
|
||||||
|
|
||||||
if (!writerWorker.logAdd(dataStrings[0], dataStrings[1], dataStrings[2])){ // Write logs, check if LogDriver consistent. If not:
|
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]);
|
this.fixLogDriverIssues(dataStrings[0], dataStrings[1], dataStrings[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endThread) {
|
|
||||||
reader.close();
|
|
||||||
chanList.get(channelName).close();
|
|
||||||
chanList.remove(channelName);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
channels.remove(channelName);
|
||||||
} catch (java.io.IOException e){
|
} catch (InterruptedException e){
|
||||||
System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->run(): Internal issue in thread: caused I/O exception:\n\t"+e); // TODO: reconnect
|
System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->run(): Interrupted\n\t"+e); // TODO: reconnect?
|
||||||
}
|
}
|
||||||
writerWorker.close();
|
writerWorker.close();
|
||||||
//Chanel commander thread's pipe should be closed
|
//Kill sub-thread
|
||||||
chanelCommanderPipe.close();
|
channelCommanderThread.interrupt();
|
||||||
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] THREAD "+serverName+":"+this.channelName +" ended"); // TODO:REMOVE DEBUG
|
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
|
case "PRIVMSG": // most common, we don't have to handle anything else
|
||||||
return true;
|
return true;
|
||||||
case "JOIN":
|
case "JOIN":
|
||||||
addUsers(simplifyNick(initiatorArg));
|
addUser(simplifyNick(initiatorArg));
|
||||||
return true;
|
return true;
|
||||||
case "PART":
|
case "PART":
|
||||||
delUsers(simplifyNick(initiatorArg)); // nick non-simple
|
deleteUser(simplifyNick(initiatorArg)); // nick non-simple
|
||||||
return true;
|
return true;
|
||||||
case "QUIT":
|
case "QUIT":
|
||||||
if (userList.contains(simplifyNick(initiatorArg))) {
|
if (userList.contains(simplifyNick(initiatorArg))) {
|
||||||
delUsers(simplifyNick(initiatorArg)); // nick non-simple
|
deleteUser(simplifyNick(initiatorArg)); // nick non-simple
|
||||||
return true;
|
return true;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
return false; // user quit, but he/she is not in this channel
|
return false; // user quit, but he/she is not in this channel
|
||||||
case "KICK":
|
case "KICK":
|
||||||
if (rejoin && nick.equals(subjectArg.replaceAll("(^.+?\\s)|(\\s.+$)", ""))) // if it's me and I have rejoin policy 'Auto-Rejoin on 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);
|
StreamProvider.writeToStream(serverName, "JOIN " + channelName);
|
||||||
delUsers(subjectArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")); // nick already simplified
|
deleteUser(subjectArg.replaceAll("(^.+?\\s)|(\\s.+$)", "")); // nick already simplified
|
||||||
return true;
|
return true;
|
||||||
case "NICK":
|
case "NICK":
|
||||||
if (userList.contains(simplifyNick(initiatorArg))) {
|
if (userList.contains(simplifyNick(initiatorArg))) {
|
||||||
swapUsers(simplifyNick(initiatorArg), subjectArg);
|
swapUsers(simplifyNick(initiatorArg), subjectArg);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return false; // user changed nick, but he/she is not in this channel
|
return false; // user changed nick, but he/she is not in this channel
|
||||||
}
|
}
|
||||||
|
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:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addUsers(String user){
|
private void addUser(String user){
|
||||||
if (!userList.contains(user))
|
if (!userList.contains(user))
|
||||||
userList.add(user);
|
userList.add(user);
|
||||||
}
|
}
|
||||||
private void delUsers(String user){
|
private void deleteUser(String user){
|
||||||
if (user.equals(nick)) {
|
if (user.equals(nick)) {
|
||||||
endThread = true;
|
endThread = true;
|
||||||
}
|
}
|
||||||
|
@ -129,33 +141,12 @@ public class ChanConsumer implements Runnable {
|
||||||
if (userNickOld.equals(nick))
|
if (userNickOld.equals(nick))
|
||||||
this.nick = userNickNew;
|
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 String simplifyNick(String nick){ return nick.replaceAll("!.*$",""); }
|
||||||
|
|
||||||
private void fixLogDriverIssues(String a, String b, String c){
|
private void fixLogDriverIssues(String a, String b, String c){
|
||||||
System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->fixLogDriverIssues(): Some issues detected. Trying to fix...");
|
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
|
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();
|
this.writerWorker = BotDriver.getZeroWorker();
|
||||||
System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->fixLogDriverIssues(): failed to use defined LogDriver. Using ZeroWorker instead.");
|
System.out.println("ChanConsumer (@"+serverName+"/"+channelName+")->fixLogDriverIssues(): failed to use defined LogDriver. Using ZeroWorker instead.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package InnaIrcBot.ProvidersConsumers;
|
package InnaIrcBot.ProvidersConsumers;
|
||||||
|
|
||||||
import InnaIrcBot.Config.StorageFile;
|
import InnaIrcBot.config.ConfigurationFile;
|
||||||
|
import InnaIrcBot.IrcChannel;
|
||||||
import InnaIrcBot.LogDriver.BotDriver;
|
import InnaIrcBot.LogDriver.BotDriver;
|
||||||
import InnaIrcBot.ReconnectControl;
|
import InnaIrcBot.ReconnectControl;
|
||||||
|
|
||||||
|
@ -8,131 +9,94 @@ import java.io.*;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
public class DataProvider implements Runnable {
|
public class DataProvider implements Runnable {
|
||||||
private StorageFile configFile;
|
private final ConfigurationFile configurationFile;
|
||||||
private String serverName;
|
private final String serverName;
|
||||||
private String userNick;
|
private final String nickName;
|
||||||
private BufferedReader rawStreamReader;
|
private BufferedReader rawStreamReader;
|
||||||
|
|
||||||
private boolean ableToRun = true;
|
|
||||||
/**
|
/**
|
||||||
* Initiate connection and prepare input/output streams for run()
|
* Initiate connection and prepare input/output streams for run()
|
||||||
* */
|
* */
|
||||||
public DataProvider(StorageFile storageFile){
|
public DataProvider(ConfigurationFile configurationFile){
|
||||||
this.configFile = storageFile;
|
this.configurationFile = configurationFile;
|
||||||
this.serverName = storageFile.getServerName();
|
this.serverName = configurationFile.getServerName();
|
||||||
|
this.nickName = configurationFile.getUserNick();
|
||||||
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 void run(){
|
public void run(){
|
||||||
if (!ableToRun || !this.initConnection(rawStreamReader)
|
try {
|
||||||
|| !BotDriver.setLogDriver(serverName, configFile.getLogDriver(), configFile.getLogDriverParameters(), configFile.getApplicationLogDir())) { //Prepare logDriver for using in threads.
|
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();
|
this.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used for sending data into consumers objects*/
|
/* Used for sending data into consumers objects*/
|
||||||
Map<String, PrintWriter> channelsMap = Collections.synchronizedMap(new HashMap<String, PrintWriter>());
|
Map<String, IrcChannel> ircChannels = Collections.synchronizedMap(new HashMap<>());
|
||||||
try {
|
|
||||||
PipedOutputStream streamOut = new PipedOutputStream(); // K-K-K-KOMBO \m/
|
|
||||||
|
|
||||||
BufferedReader streamBufferedReader = new BufferedReader(
|
IrcChannel systemConsumerChannel = new IrcChannel("");
|
||||||
new InputStreamReader(
|
BlockingQueue<String> systemConsumerQueue = systemConsumerChannel.getChannelQueue();
|
||||||
new PipedInputStream(streamOut), StandardCharsets.UTF_8)
|
|
||||||
);
|
|
||||||
|
|
||||||
Runnable systemConsumer = new SystemConsumer(streamBufferedReader, userNick, channelsMap, this.configFile);
|
Thread SystemConsumerThread = new Thread(
|
||||||
new Thread(systemConsumer).start();
|
new SystemConsumer(systemConsumerQueue, nickName, ircChannels, this.configurationFile));
|
||||||
PrintWriter systemConsumerWriter = new PrintWriter(streamOut);
|
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..
|
ircChannels.put(systemConsumerChannel.toString(), systemConsumerChannel); // 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;
|
|
||||||
}
|
|
||||||
////////////////////////////////////// Start loop //////////////////////////////////////////////////////////////
|
////////////////////////////////////// Start loop //////////////////////////////////////////////////////////////
|
||||||
|
StreamProvider.writeToStream(serverName,"NICK "+this.nickName);
|
||||||
|
StreamProvider.writeToStream(serverName,"USER "+ configurationFile.getUserIdent()+" 8 * :"+ configurationFile.getUserRealName()); // TODO: Add usermode 4 rusnet
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String rawMessage;
|
String rawMessage;
|
||||||
String[] rawStrings; // prefix[0] command[1] command-parameters\r\n[2]
|
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.
|
//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) {
|
while ((rawMessage = rawStreamReader.readLine()) != null) {
|
||||||
//System.out.println(rawMessage);
|
System.out.println(rawMessage);
|
||||||
if (rawMessage.startsWith(":")) {
|
if (rawMessage.startsWith(":")) {
|
||||||
rawStrings = rawMessage
|
rawStrings = rawMessage
|
||||||
.substring(1)
|
.substring(1)
|
||||||
.split(" :?", 3); // Removing ':'
|
.split(" :?", 3); // Removing ':'
|
||||||
|
|
||||||
|
String chan = rawStrings[2].replaceAll("(\\s.?$)|(\\s.+?$)", "");
|
||||||
chan = rawStrings[2].replaceAll("(\\s.?$)|(\\s.+?$)", "");
|
|
||||||
|
|
||||||
//System.out.println("\tChannel: "+chan+"\n\tAction: "+rawStrings[1]+"\n\tSender: "+rawStrings[0]+"\n\tMessage: "+rawStrings[2]+"\n");
|
//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
|
if (rawStrings[1].equals("QUIT") || rawStrings[1].equals("NICK")) { // replace regex
|
||||||
for (PrintWriter value : channelsMap.values()) {
|
for (IrcChannel ircChannel : ircChannels.values()) {
|
||||||
value.println(rawStrings[1] + " " + rawStrings[0] + " " + rawStrings[2]);
|
ircChannel.getChannelQueue().add(rawStrings[1] + " " + rawStrings[0] + " " + rawStrings[2]);
|
||||||
value.flush();
|
|
||||||
}
|
}
|
||||||
} 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 :")) {
|
else if (ircChannels.containsKey(chan)) {
|
||||||
pingSrvResponse(rawMessage);
|
IrcChannel chnl = ircChannels.get(chan);
|
||||||
} else {
|
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);
|
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
|
System.out.println("Socket issue: I/O exception"); //Connection closed. TODO: MAYBE try reconnect
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
for (PrintWriter p :channelsMap.values()) {
|
SystemConsumerThread.interrupt();
|
||||||
p.close();
|
close();
|
||||||
}
|
|
||||||
this.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 :", ""));
|
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();
|
//HANDLE ALWAYS in case thread decided to die
|
||||||
|
private void close(){
|
||||||
if (this.userNick == null || this.userNick.isEmpty()) {
|
StreamProvider.delStream(serverName);
|
||||||
System.out.println("Configuration issue: no nickname specified.");
|
ReconnectControl.notify(serverName);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,39 @@
|
||||||
package InnaIrcBot.ProvidersConsumers;
|
package InnaIrcBot.ProvidersConsumers;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
|
||||||
public class StreamProvider {
|
public class StreamProvider {
|
||||||
|
|
||||||
private static HashMap<String, OutputStreamWriter> srvStreamMap = new HashMap<>();
|
private static final HashMap<String, OutputStreamWriter> srvStreamMap = new HashMap<>();
|
||||||
private static HashMap<String, PrintWriter> srvSysConsumersMap = new HashMap<>();
|
private static final HashMap<String, BlockingQueue<String>> srvSysConsumersMap = new HashMap<>();
|
||||||
|
|
||||||
public static synchronized void writeToStream(String server, String message){
|
public static synchronized void writeToStream(String server, String message){
|
||||||
try {
|
try {
|
||||||
srvStreamMap.get(server).write(message+"\n");
|
srvStreamMap.get(server).write(message+"\n");
|
||||||
srvStreamMap.get(server).flush();
|
srvStreamMap.get(server).flush();
|
||||||
//System.out.println("W:"+message);
|
|
||||||
// If this application says something, then pass it into system consumer thread to handle
|
// If this application says something, then pass it into system consumer thread to handle
|
||||||
if (message.startsWith("PRIVMSG ")) {
|
if (message.startsWith("PRIVMSG ")) {
|
||||||
srvSysConsumersMap.get(server).println("INNA "+message);
|
srvSysConsumersMap.get(server).add("INNA "+message);
|
||||||
srvSysConsumersMap.get(server).flush();
|
|
||||||
}
|
}
|
||||||
} catch (java.io.IOException e){
|
} catch (IOException e){
|
||||||
System.out.println("Internal issue: StreamProvider->writeToStream() caused I/O exception:\n\t"+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){
|
public static synchronized void setStream(String server, Socket socket) throws IOException{
|
||||||
try {
|
|
||||||
OutputStream outStream = socket.getOutputStream();
|
OutputStream outStream = socket.getOutputStream();
|
||||||
srvStreamMap.put(server, new OutputStreamWriter(outStream));
|
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 delStream(String server){
|
public static synchronized void delStream(String server){
|
||||||
srvStreamMap.remove(server);
|
srvStreamMap.remove(server);
|
||||||
srvSysConsumersMap.remove(server);
|
srvSysConsumersMap.remove(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized void setSysConsumer(String server, PrintWriter pw){
|
public static synchronized void setSysConsumer(String server, BlockingQueue<String> queue){
|
||||||
srvSysConsumersMap.put(server, pw);
|
srvSysConsumersMap.put(server, queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,56 +2,45 @@ package InnaIrcBot.ProvidersConsumers;
|
||||||
|
|
||||||
import InnaIrcBot.Commanders.CTCPHelper;
|
import InnaIrcBot.Commanders.CTCPHelper;
|
||||||
import InnaIrcBot.Commanders.PrivateMsgCommander;
|
import InnaIrcBot.Commanders.PrivateMsgCommander;
|
||||||
import InnaIrcBot.Config.StorageFile;
|
import InnaIrcBot.ReconnectControl;
|
||||||
|
import InnaIrcBot.config.ConfigurationFile;
|
||||||
import InnaIrcBot.GlobalData;
|
import InnaIrcBot.GlobalData;
|
||||||
|
import InnaIrcBot.IrcChannel;
|
||||||
import InnaIrcBot.LogDriver.BotDriver;
|
import InnaIrcBot.LogDriver.BotDriver;
|
||||||
import InnaIrcBot.LogDriver.BotSystemWorker;
|
import InnaIrcBot.LogDriver.BotSystemWorker;
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
|
||||||
public class SystemConsumer implements Runnable{
|
public class SystemConsumer implements Runnable{
|
||||||
private BufferedReader reader;
|
private final BlockingQueue<String> systemQueue;
|
||||||
private BotSystemWorker writerWorker;
|
private BotSystemWorker writerWorker;
|
||||||
private String nick;
|
private String nick;
|
||||||
private String serverName;
|
private String serverName;
|
||||||
private Map<String, PrintWriter> channelsMap;
|
private final Map<String, IrcChannel> channels;
|
||||||
private boolean proxyRequired;
|
private ConfigurationFile configurationFile;
|
||||||
private HashMap<String, ArrayList<String>> proxyAList;
|
|
||||||
private StorageFile storageFile;
|
|
||||||
|
|
||||||
private PrivateMsgCommander commander;
|
private PrivateMsgCommander commander;
|
||||||
|
|
||||||
private LocalDateTime lastCTCPReplyTime;
|
private LocalDateTime lastCTCPReplyTime;
|
||||||
|
|
||||||
SystemConsumer(BufferedReader streamReader, String userNick, Map<String, PrintWriter> map, StorageFile storage) {
|
private ArrayList<Thread> channelThreads;
|
||||||
this.writerWorker = BotDriver.getSystemWorker(storage.getServerName());
|
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.nick = userNick;
|
||||||
this.serverName = storage.getServerName();
|
this.serverName = configurationFile.getServerName();
|
||||||
this.channelsMap = map;
|
this.channels = channels;
|
||||||
this.reader = streamReader;
|
this.channelThreads = new ArrayList<>();
|
||||||
|
this.configurationFile = configurationFile;
|
||||||
this.proxyRequired = false;
|
this.commander = new PrivateMsgCommander(serverName, this.configurationFile.getBotAdministratorPassword());
|
||||||
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());
|
|
||||||
|
|
||||||
lastCTCPReplyTime = LocalDateTime.now();
|
lastCTCPReplyTime = LocalDateTime.now();
|
||||||
}
|
}
|
||||||
|
@ -62,38 +51,32 @@ public class SystemConsumer implements Runnable{
|
||||||
|
|
||||||
setMainRoutine();
|
setMainRoutine();
|
||||||
|
|
||||||
for (PrintWriter p :channelsMap.values()) //TODO: check, code duplication. see Data provider constructor
|
for (Thread channel : channelThreads) { //TODO: check, code duplication. see Data provider constructor
|
||||||
p.close();
|
channel.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
writerWorker.close();
|
writerWorker.close();
|
||||||
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] THREAD "+serverName+":[system] ended"); // TODO:REMOVE DEBUG
|
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] THREAD "+serverName+":[system] ended"); // TODO:REMOVE DEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setMainRoutine(){
|
private void setMainRoutine(){
|
||||||
String data;
|
|
||||||
String[] dataStrings;
|
|
||||||
try {
|
try {
|
||||||
while ((data = reader.readLine()) != null) {
|
while (true) {
|
||||||
dataStrings = data.split(" ",3);
|
String data = systemQueue.take();
|
||||||
|
String[] dataStrings = data.split(" ",3);
|
||||||
if (proxyRequired)
|
//TODO: handle mode change
|
||||||
if (getProxy(dataStrings[0], dataStrings[1], dataStrings[2]))
|
switch (dataStrings[0]){
|
||||||
continue; // TODO: check this. Continue is fair?
|
case "PRIVMSG":
|
||||||
|
|
||||||
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")) {
|
if (dataStrings[2].indexOf("\u0001") < dataStrings[2].lastIndexOf("\u0001")) {
|
||||||
replyCTCP(simplifyNick(dataStrings[1]), dataStrings[2].substring(dataStrings[2].indexOf(":") + 1));
|
replyCTCP(simplifyNick(dataStrings[1]), dataStrings[2].substring(dataStrings[2].indexOf(":") + 1));
|
||||||
//System.out.println("|"+dataStrings[1]+"|"+dataStrings[2].substring(dataStrings[2].indexOf(":") + 1)+"|");
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
commander.receiver(dataStrings[1], dataStrings[2].replaceAll("^.+?:", "").trim());
|
commander.receiver(dataStrings[1], dataStrings[2].replaceAll("^.+?:", "").trim());
|
||||||
writerWorker.logAdd("[system]", "PRIVMSG from "+dataStrings[1]+" received: ", dataStrings[2].replaceAll("^.+?:", "").trim());
|
writerWorker.logAdd("[system]", "PRIVMSG from "+dataStrings[1]+" received: ",
|
||||||
|
dataStrings[2].replaceAll("^.+?:", "").trim());
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
else if (dataStrings[0].equals("INNA")) {
|
case "INNA":
|
||||||
String[] splitter;
|
String[] splitter;
|
||||||
if (dataStrings.length > 2){ // Don't touch 'cuz it's important
|
if (dataStrings.length > 2){ // Don't touch 'cuz it's important
|
||||||
splitter = dataStrings[2].split(" ", 2);
|
splitter = dataStrings[2].split(" ", 2);
|
||||||
|
@ -101,120 +84,82 @@ public class SystemConsumer implements Runnable{
|
||||||
handleSpecial(dataStrings[1], splitter[0], splitter[1]);
|
handleSpecial(dataStrings[1], splitter[0], splitter[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
else
|
default:
|
||||||
writerWorker.logAdd(dataStrings[0], dataStrings[1], dataStrings[2]); // TODO: Track users
|
handleNumeric(dataStrings[0], dataStrings[1], dataStrings[2]);
|
||||||
//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.
|
|
||||||
}
|
}
|
||||||
else {
|
catch (InterruptedException ie){
|
||||||
//writerWorker.logAdd("[proxy]", "catch: "+eventNum+" from: "+sender+" :",message);
|
System.out.println("Thread SystemConsumer->run() interrupted."); // TODO: reconnect OR AT LEAST DIE
|
||||||
String chan = message.replaceAll("(\\s.?$)|(\\s.+?$)", "");
|
}
|
||||||
|
catch (Exception e){
|
||||||
if (eventNum.equals("QUIT") || eventNum.equals("NICK")) {
|
System.out.println("Internal issue: thread SystemConsumer->run(): "+e.getMessage()); // TODO: DO.. some thing
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void replyCTCP(String sender, String message){ // got simplified nick
|
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
|
// TODO: Consider moving to config file. Now set to 3 sec
|
||||||
|
if (lastCTCPReplyTime.isAfter(LocalDateTime.now().minusSeconds(3)))
|
||||||
|
return;
|
||||||
|
|
||||||
lastCTCPReplyTime = LocalDateTime.now();
|
lastCTCPReplyTime = LocalDateTime.now();
|
||||||
if (message.equals("\u0001VERSION\u0001")) {
|
|
||||||
|
switch (message) {
|
||||||
|
case "\u0001VERSION\u0001":
|
||||||
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001VERSION " + GlobalData.getAppVersion() + "\u0001");
|
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001VERSION " + GlobalData.getAppVersion() + "\u0001");
|
||||||
writerWorker.logAdd("[system]", "catch/handled CTCP VERSION from", sender);
|
writerWorker.logAdd("[system]", "catch/handled CTCP VERSION from", sender);
|
||||||
//System.out.println("NOTICE "+sender+" \u0001VERSION "+ GlobalData.getAppVersion()+"\u0001");
|
return;
|
||||||
} else if (message.startsWith("\u0001PING ") && message.endsWith("\u0001")) {
|
case "\u0001CLIENTINFO\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")) {
|
|
||||||
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO SOURCE\u0001");
|
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO SOURCE\u0001");
|
||||||
writerWorker.logAdd("[system]", "catch/handled CTCP CLIENTINFO from", sender);
|
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");
|
return;
|
||||||
} else if (message.equals("\u0001TIME\u0001")) {
|
case "\u0001TIME\u0001":
|
||||||
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001TIME " + ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME) + "\u0001");
|
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001TIME " + ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME) + "\u0001");
|
||||||
writerWorker.logAdd("[system]", "catch/handled CTCP TIME from", sender);
|
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");
|
return;
|
||||||
} else if (message.equals("\u0001SOURCE\u0001")) {
|
case "\u0001SOURCE\u0001":
|
||||||
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001SOURCE https://github.com/developersu/InnaIrcBot\u0001");
|
StreamProvider.writeToStream(serverName, "NOTICE " + sender + " :\u0001SOURCE https://github.com/developersu/InnaIrcBot\u0001");
|
||||||
writerWorker.logAdd("[system]", "catch/handled CTCP TIME from", sender);
|
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");
|
return;
|
||||||
} else
|
|
||||||
writerWorker.logAdd("[system]", "catch unknown CTCP request \"" + message + "\" from ", sender);
|
|
||||||
}
|
}
|
||||||
|
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 String simplifyNick(String nick){ return nick.replaceAll("!.*$",""); }
|
||||||
|
|
||||||
private void handleSpecial(String event, String chanel, String message){
|
private void handleSpecial(String event, String channelName, String message){
|
||||||
//System.out.println("|"+event+"|"+chanel+"|"+message+"|");
|
IrcChannel ircChannel = channels.get(channelName);
|
||||||
if (channelsMap.containsKey(chanel)){
|
if (ircChannel == null)
|
||||||
channelsMap.get(chanel).println(event+" "+nick+" "+chanel+" "+message); // WTF ><
|
return;
|
||||||
channelsMap.get(chanel).flush();
|
String ircFormatterMessage = event+" "+nick+" "+channelName+" "+message;
|
||||||
//System.out.println("Formatted: |"+event+"|"+nick+"|"+chanel+" "+message+"|");
|
//System.out.println("Formatted: |"+event+"|"+nick+"|"+channelName+" "+message+"|");
|
||||||
|
ircChannel.getChannelQueue().add(ircFormatterMessage);
|
||||||
}
|
}
|
||||||
}
|
//todo: handle nickserv messages somehow
|
||||||
//todo: nandle nickserv messages
|
private void handleNumeric(String eventNum, String sender, String message) throws Exception{
|
||||||
private void handleNumeric(String eventNum, String sender, String message){
|
|
||||||
switch (eventNum){
|
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
|
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;
|
break;
|
||||||
case "353":
|
case "353":
|
||||||
writerWorker.logAdd("[system]", "catch/handled:", eventNum+" [RPL_NAMREPLY]");
|
writerWorker.logAdd("[system]", "catch/handled:", eventNum+" [RPL_NAMREPLY]");
|
||||||
String chan = message.substring(message.indexOf(" ")+3);
|
String channelName = message.substring(nick.length()+3).replaceAll("\\s.*$", "");
|
||||||
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(" ");
|
|
||||||
|
|
||||||
PipedOutputStream streamOut = new PipedOutputStream();
|
IrcChannel ircChannel = channels.get(channelName);
|
||||||
try {
|
if (ircChannel == null)
|
||||||
BufferedReader streamBufferedReader = new BufferedReader(
|
return;
|
||||||
new InputStreamReader(
|
ircChannel.getChannelQueue().add(eventNum+" "+sender+" "+message);
|
||||||
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+"|");
|
|
||||||
break;
|
break;
|
||||||
case "NICK":
|
case "NICK":
|
||||||
if (sender.startsWith(nick+"!")) {
|
if (sender.startsWith(nick+"!")) {
|
||||||
|
@ -224,9 +169,19 @@ public class SystemConsumer implements Runnable{
|
||||||
break;
|
break;
|
||||||
case "JOIN":
|
case "JOIN":
|
||||||
if (sender.startsWith(nick+"!")) {
|
if (sender.startsWith(nick+"!")) {
|
||||||
proxyAList.put(message, new ArrayList<>()); // Add new channel name to proxy watch-list
|
IrcChannel newIrcChannel = new IrcChannel(message);
|
||||||
proxyAList.get(message).add(eventNum+" "+sender+" "+message); // Add message to array linked
|
|
||||||
this.proxyRequired = true; // Ask for proxy validators
|
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);
|
writerWorker.logAdd("[system]", "joined to channel ", message);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -239,11 +194,79 @@ public class SystemConsumer implements Runnable{
|
||||||
CTCPHelper.getInstance().handleCtcpReply(serverName, simplifyNick(sender), message.replaceAll("^.+?:", "").trim());
|
CTCPHelper.getInstance().handleCtcpReply(serverName, simplifyNick(sender), message.replaceAll("^.+?:", "").trim());
|
||||||
writerWorker.logAdd("[system]", "NOTICE from "+sender+" received: ", message.replaceAll("^.+?:", "").trim());
|
writerWorker.logAdd("[system]", "NOTICE from "+sender+" received: ", message.replaceAll("^.+?:", "").trim());
|
||||||
break;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
writerWorker.logAdd("[system]", "catch: "+eventNum+" from: "+sender+" :",message); // TODO: QUIT comes here. Do something?
|
writerWorker.logAdd("[system]", "catch: "+eventNum+" from: "+sender+" :",message);
|
||||||
break;
|
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;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class ReconnectControl {
|
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){
|
public static synchronized void register(String serverName){
|
||||||
serversList.put(serverName, true);
|
serversList.put(serverName, true);
|
||||||
}
|
}
|
||||||
public static synchronized void update(String serverName, boolean needReconnect){
|
public static synchronized void update(String serverName, boolean needReconnect){
|
||||||
serversList.replace(serverName, 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)
|
public static synchronized void notify(String serverName) {
|
||||||
return false;
|
if (serversList.get(serverName) == null || ! serversList.get(serverName)){
|
||||||
else
|
|
||||||
return serversList.get(serverName);
|
|
||||||
}
|
|
||||||
public static synchronized void delete(String serverName){
|
|
||||||
serversList.remove(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;
|
package Temporary;
|
||||||
|
|
||||||
import InnaIrcBot.Config.StorageFile;
|
import InnaIrcBot.config.ConfigurationFile;
|
||||||
|
|
||||||
public class StorageFileTest {
|
public class StorageFileTest {
|
||||||
static public void main(String[] args){
|
static public void main(String[] args){
|
||||||
StorageFile config = new StorageFile(
|
ConfigurationFile config = new ConfigurationFile(
|
||||||
"",
|
"",
|
||||||
0,
|
0,
|
||||||
"",
|
"",
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
package Temporary;
|
package Temporary;
|
||||||
|
|
||||||
import InnaIrcBot.Config.StorageFile;
|
|
||||||
import InnaIrcBot.Config.StorageReader;
|
|
||||||
|
|
||||||
public class StorageReaderTest {
|
public class StorageReaderTest {
|
||||||
public static void main(String[] args){
|
public static void main(String[] args){
|
||||||
// StorageReader.readConfig("/home/loper/bot.config");
|
// 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