innaircbot/src/main/java/InnaIrcBot/ProvidersConsumers/SystemConsumer.java

206 lines
10 KiB
Java

package InnaIrcBot.ProvidersConsumers;
import InnaIrcBot.Commanders.PrivateMsgCommander;
import InnaIrcBot.Config.StorageFile;
import InnaIrcBot.GlobalData;
import InnaIrcBot.LogDriver.BotDriver;
import InnaIrcBot.LogDriver.Worker;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
public class SystemConsumer implements Runnable{
private BufferedReader reader;
private Worker writerWorker;
private String nick;
private String serverName;
private Map<String, PrintWriter> channelsMap;
private boolean proxyRequired;
private HashMap<String, ArrayList<String>> proxyAList;
private StorageFile storageFile;
private PrivateMsgCommander commander;
SystemConsumer(BufferedReader streamReader, String userNick, Map<String, PrintWriter> map, StorageFile storage) {
this.writerWorker = BotDriver.getWorker(storage.getServerName(), "system");
this.nick = userNick;
this.serverName = storage.getServerName();
this.channelsMap = map;
this.reader = streamReader;
this.proxyRequired = false;
this.proxyAList = new HashMap<>();
this.storageFile = storage;
this.commander = new PrivateMsgCommander(serverName, storageFile.getBotAdministratorPassword());
// Start pre-set channels
StringBuilder message = new StringBuilder();
for (String cnl : storageFile.getChannels()) { // TODO: add validation of channels.
message.append("JOIN ");
message.append(cnl);
message.append("\n");
}
StreamProvider.writeToStream(serverName,message.toString());
}
@Override
public void run() {
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] THREAD "+serverName+":[system] started"); // TODO:REMOVE DEBUG
setMainRoutine();
for (PrintWriter p :channelsMap.values()) //TODO: check, code duplication. see Data provider constructor
p.close();
writerWorker.close();
System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] THREAD "+serverName+":[system] ended"); // TODO:REMOVE DEBUG
}
private void setMainRoutine(){
String data;
String dataStrings[];
try {
while ((data = reader.readLine()) != null) {
dataStrings = data.split(" ",3);
if (proxyRequired)
if (getProxy(dataStrings[0], dataStrings[1], dataStrings[2]))
continue;
if (dataStrings[0].equals("PRIVMSG") && dataStrings[2].indexOf("\u0001") < dataStrings[2].lastIndexOf("\u0001"))
replyCTCP(dataStrings[1], dataStrings[2].substring(dataStrings[2].indexOf(":")+1));
else if (Pattern.matches("(^[0-9]{3}$)|(^NICK$)|(^JOIN$)", dataStrings[0])){
handleNumeric(dataStrings[0], dataStrings[1], dataStrings[2]);
}
else if (dataStrings[0].equals("PRIVMSG")) {
commander.receiver(dataStrings[1], dataStrings[2].replaceAll("^.+?:", "").trim());
writerWorker.logAdd("[system]", "PRIVMSG sent to", "commander");
}
else
writerWorker.logAdd(dataStrings[0], dataStrings[1], dataStrings[2]); // TODO: Track users
//System.out.println("System: "+"|"+dataStrings[0]+"|"+dataStrings[1]+"|"+dataStrings[2]+"|");
}
} catch (java.io.IOException e){
System.out.println("Internal issue: thread SystemConsumer->run() caused I/O exception."); // TODO: reconnect
}
}
private boolean getProxy(String eventNum, String sender, String message){ //TODO: if can't join: like channel with password
if (eventNum.equals("353"))
return false; // never mind and let it flows as usual.
else {
String chan = message.replaceAll("(\\s.?$)|(\\s.+?$)", "");
if (eventNum.equals("QUIT") || eventNum.equals("NICK")) {
for (ArrayList<String> key : proxyAList.values())
key.add(eventNum + " " + sender + " " + message);
return false;
} else if (chan.equals(nick))
return false;
else if (proxyAList.keySet().contains(chan)) {
proxyAList.get(chan).add(eventNum + " " + sender + " " + message);
return true;
} else
return false;
}
}
private void replyCTCP(String sender, String message){
if (message.equals("\u0001VERSION\u0001")){
StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :\u0001VERSION "+ GlobalData.getAppVersion()+"\u0001");
writerWorker.logAdd("[system]", "catch/handled CTCP VERSION from", simplifyNick(sender));
System.out.println(sender+" "+message);
System.out.println("NOTICE "+simplifyNick(sender)+" \u0001VERSION "+ GlobalData.getAppVersion()+"\u0001");
}
else if (message.startsWith("\u0001PING ") && message.endsWith("\u0001")){
StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :"+message);
writerWorker.logAdd("[system]", "catch/handled CTCP PING from", simplifyNick(sender));
//System.out.println(":"+simplifyNick(sender)+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" "+message);
}
else if (message.equals("\u0001CLIENTINFO\u0001")){
StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :\u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO\u0001");
writerWorker.logAdd("[system]", "catch/handled CTCP CLIENTINFO from", simplifyNick(sender));
//System.out.println(":"+simplifyNick(sender)+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" \u0001CLIENTINFO ACTION PING VERSION TIME CLIENTINFO\u0001");
}
else if (message.equals("\u0001TIME\u0001")){
StreamProvider.writeToStream(serverName,"NOTICE "+simplifyNick(sender)+" :\u0001TIME "+ ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\u0001");
writerWorker.logAdd("[system]", "catch/handled CTCP TIME from", simplifyNick(sender));
//System.out.println(":"+simplifyNick(sender)+" NOTICE "+sender.substring(0,sender.indexOf("!"))+" \u0001TIME "+ ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\u0001");
} else
writerWorker.logAdd("[system]", "catch CTCP request \""+message+"\" from ", simplifyNick(sender));
}
private String simplifyNick(String nick){ return nick.replaceAll("!.*$",""); }
//todo: nandle nickserv messages
private void handleNumeric(String eventNum, String sender, String message){
switch (eventNum){
case "433": // TODO: try to use alternative nickname
writerWorker.logAdd("[system]", "catch/handled:", eventNum+" [nickname already in use]");
break;
case "353":
String chan = message.substring(message.indexOf(" ")+3);
chan = chan.substring(0, chan.indexOf(" "));
if (proxyAList.containsKey(chan)) {
String userOnChanStr = message.substring(message.indexOf(":") + 1);
userOnChanStr = userOnChanStr.replaceAll("[%@+]", "").trim();
String[] usersOnChanArr = userOnChanStr.split(" ");
PipedOutputStream streamOut = new PipedOutputStream();
try {
BufferedReader streamBufferedReader = new BufferedReader(
new InputStreamReader(
new PipedInputStream(streamOut), StandardCharsets.UTF_8)
);
channelsMap.put(chan, new PrintWriter(streamOut));
// % @ +
ChanConsumer consumer = new ChanConsumer(streamBufferedReader, storageFile.getServerName(), chan, nick, usersOnChanArr, storageFile.getRejoinOnKick(), channelsMap, storageFile.getChanelConfigurationsPath());
new Thread(consumer).start();
for (String msgStored : proxyAList.get(chan)) {
channelsMap.get(chan).println(msgStored);
channelsMap.get(chan).flush();
}
proxyAList.remove(chan);
if (proxyAList.isEmpty()) {
proxyRequired = false;
}
} catch (IOException e) {
System.out.println("Internal issue: SystemConsumer->handleNumeric() @ JOIN: I/O exception while initialized child objects."); // caused by Socket
return; //TODO: QA
}
}
else
System.out.println("Some internal shit happens that shouldn't happens never ever. Take your cat, call scientists and wait for singularity. Panic allowed.");
break;
case "NICK":
if (sender.startsWith(nick+"!")) {
String oldNick = nick;
nick = message.trim();
writerWorker.logAdd("[system]", "catch/handled own NICK change from:", sender+" to: "+message);
}
break;
case "JOIN":
if (sender.startsWith(nick+"!")) {
proxyAList.put(message, new ArrayList<>()); // Add new channel name to proxy watch-list
proxyAList.get(message).add(eventNum+" "+sender+" "+message); // Add message to array linked
this.proxyRequired = true; // Ask for proxy validators
}
break;
default:
writerWorker.logAdd("[system]", "catch: "+eventNum+" from: "+sender+" :",message);
break;
}
}
}