2018-12-16 17:27:44 +03:00
package InnaIrcBot.ProvidersConsumers ;
import InnaIrcBot.Commanders.ChanelCommander ;
import InnaIrcBot.LogDriver.BotDriver ;
import InnaIrcBot.LogDriver.Worker ;
import java.io.* ;
import java.nio.charset.StandardCharsets ;
import java.time.LocalTime ;
import java.time.format.DateTimeFormatter ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.Map ;
public class ChanConsumer implements Runnable {
private BufferedReader reader ;
private String serverName ;
private String channelName ;
private Worker writerWorker ;
private ArrayList < String > userList ;
private String nick ;
private boolean rejoin ;
private Map < String , PrintWriter > chanList ;
private String configFilePath ;
private PrintWriter chanelCommanderPipe ;
private boolean endThread = false ;
ChanConsumer ( BufferedReader streamReader , String serverName , String channelName , String ownNick , String [ ] usersOnChan , boolean rejoinAlways , Map < String , PrintWriter > map , String configFilePath ) {
this . reader = streamReader ;
this . serverName = serverName ;
this . channelName = channelName ;
this . writerWorker = BotDriver . getWorker ( serverName , channelName ) ;
this . userList = new ArrayList < > ( ) ;
this . userList . addAll ( Arrays . asList ( usersOnChan ) ) ;
this . nick = ownNick ;
this . rejoin = rejoinAlways ;
this . chanList = map ;
this . configFilePath = configFilePath ;
// Create chanel commander thread, get pipe
this . chanelCommanderPipe = getChanelCommander ( ) ;
}
public void run ( ) {
String data ;
String [ ] dataStrings ;
System . out . println ( " [ " + LocalTime . now ( ) . format ( DateTimeFormatter . ofPattern ( " HH:mm:ss " ) ) + " ] THREAD " + serverName + " : " + this . channelName + " started " ) ; // TODO:REMOVE DEBUG
try {
while ( ( data = reader . readLine ( ) ) ! = null ) {
dataStrings = data . split ( " " , 3 ) ;
if ( ! trackUsers ( dataStrings [ 0 ] , dataStrings [ 1 ] , dataStrings [ 2 ] ) )
continue ;
// Send to chanel commander thread
chanelCommanderPipe . println ( data ) ;
chanelCommanderPipe . flush ( ) ;
//System.out.println("|"+dataStrings[0]+"|"+dataStrings[1]+"|"+dataStrings[2]+"|");
//System.out.println("Thread: "+this.channelName +"\n\tArray:"+ userList);
2019-01-26 00:33:52 +03:00
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 ] ) ;
}
2018-12-16 17:27:44 +03:00
if ( endThread ) {
reader . close ( ) ;
chanList . get ( channelName ) . close ( ) ;
chanList . remove ( channelName ) ;
break ;
}
}
} catch ( java . io . IOException e ) {
2019-01-26 00:33:52 +03:00
System . out . println ( " ChanConsumer (@ " + serverName + " / " + channelName + " )->run(): Internal issue in thread: caused I/O exception: \ n \ t " + e ) ; // TODO: reconnect
2018-12-16 17:27:44 +03:00
}
writerWorker . close ( ) ;
//Chanel commander thread's pipe should be closed
chanelCommanderPipe . close ( ) ;
System . out . println ( " [ " + LocalTime . now ( ) . format ( DateTimeFormatter . ofPattern ( " HH:mm:ss " ) ) + " ] THREAD " + serverName + " : " + this . channelName + " ended " ) ; // TODO:REMOVE DEBUG
}
private boolean trackUsers ( String event , String initiatorArg , String subjectArg ) {
switch ( event ) {
case " PRIVMSG " : // most common, we don't have to handle anything else
return true ;
case " JOIN " :
2019-01-26 00:33:52 +03:00
addUsers ( simplifyNick ( initiatorArg ) ) ;
2018-12-16 17:27:44 +03:00
return true ;
case " PART " :
2019-01-26 00:33:52 +03:00
delUsers ( simplifyNick ( initiatorArg ) ) ; // nick non-simple
2018-12-16 17:27:44 +03:00
return true ;
2019-01-26 00:33:52 +03:00
case " QUIT " :
if ( userList . contains ( simplifyNick ( initiatorArg ) ) ) {
delUsers ( simplifyNick ( initiatorArg ) ) ; // nick non-simple
2018-12-16 17:27:44 +03:00
return true ;
} else
return false ; // user quit, but he/she is not in this channel
case " KICK " :
2019-01-26 00:33:52 +03:00
if ( rejoin & & nick . equals ( subjectArg . replaceAll ( " (^.+? \\ s)|( \\ s.+$) " , " " ) ) ) // if it's me and I have rejoin policy 'Auto-Rejoin on kick'.
2018-12-16 17:27:44 +03:00
StreamProvider . writeToStream ( serverName , " JOIN " + channelName ) ;
2019-01-26 00:33:52 +03:00
delUsers ( subjectArg . replaceAll ( " (^.+? \\ s)|( \\ s.+$) " , " " ) ) ; // nick already simplified
2018-12-16 17:27:44 +03:00
return true ;
case " NICK " :
2019-01-26 00:33:52 +03:00
if ( userList . contains ( simplifyNick ( initiatorArg ) ) ) {
swapUsers ( simplifyNick ( initiatorArg ) , subjectArg ) ;
2018-12-16 17:27:44 +03:00
return true ;
} else {
return false ; // user changed nick, but he/she is not in this channel
}
default :
return true ;
}
}
private void addUsers ( String user ) {
2019-01-26 00:33:52 +03:00
if ( ! userList . contains ( user ) )
userList . add ( user ) ;
2018-12-16 17:27:44 +03:00
}
private void delUsers ( String user ) {
2019-01-26 00:33:52 +03:00
if ( user . equals ( nick ) ) {
2018-12-16 17:27:44 +03:00
endThread = true ;
}
2019-01-26 00:33:52 +03:00
userList . remove ( user ) ;
2018-12-16 17:27:44 +03:00
}
private void swapUsers ( String userNickOld , String userNickNew ) {
2019-01-26 00:33:52 +03:00
userList . remove ( userNickOld ) ;
2018-12-16 17:27:44 +03:00
userList . add ( userNickNew ) ;
2019-01-26 00:33:52 +03:00
if ( userNickOld . equals ( nick ) )
2018-12-16 17:27:44 +03:00
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 ) {
2019-01-26 00:33:52 +03:00
System . out . println ( " ChanConsumer (@ " + serverName + " / " + channelName + " )->getChanelCommander(): Internal issue: I/O exception while initialized child objects: \ n \ t " + e ) ; // caused by Socket
2018-12-16 17:27:44 +03:00
endThread = true ;
return null ;
}
}
2019-01-26 00:33:52 +03:00
private String simplifyNick ( String nick ) { return nick . replaceAll ( " !.*$ " , " " ) ; }
private void fixLogDriverIssues ( String a , String b , String c ) {
System . out . println ( " ChanConsumer (@ " + serverName + " / " + channelName + " )->fixLogDriverIssues(): Some issues detected. Trying to fix... " ) ;
this . writerWorker = BotDriver . getWorker ( serverName , channelName ) ; // Reset logDriver and try using the same one
if ( ! writerWorker . logAdd ( a , b , c ) ) { // Write to it what was not written (most likely) and if it's still not consistent:
this . writerWorker = BotDriver . getZeroWorker ( ) ;
System . out . println ( " ChanConsumer (@ " + serverName + " / " + channelName + " )->fixLogDriverIssues(): failed to use defined LogDriver. Using ZeroWorker instead. " ) ;
}
}
2018-12-16 17:27:44 +03:00
}