Browse Source

Netty implementation now working

Tankernn 8 years ago
parent
commit
75cfc4c783

+ 8 - 0
src/main/java/eu/tankernn/chat/client/ChatClientHandler.java

@@ -7,6 +7,7 @@ import eu.tankernn.chat.common.MessagePacket;
 import eu.tankernn.chat.common.MessagePacket.MessageType;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.handler.timeout.IdleStateEvent;
 
 public class ChatClientHandler extends ChannelInboundHandlerAdapter {
 	private ChatWindow chatWindow;
@@ -35,4 +36,11 @@ public class ChatClientHandler extends ChannelInboundHandlerAdapter {
 			chatWindow.chat.log(new MessagePacket((String) fromServer, MessageType.NORMAL));
 		}
 	}
+	
+	@Override
+	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+		if (evt instanceof IdleStateEvent) {
+			ctx.writeAndFlush("/ping");
+		}
+	}
 }

+ 2 - 1
src/main/java/eu/tankernn/chat/client/ChatWindow.java

@@ -11,7 +11,6 @@ import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.awt.event.WindowEvent;
 import java.awt.event.WindowListener;
-import java.awt.event.WindowStateListener;
 import java.io.File;
 import java.util.ArrayList;
 
@@ -42,6 +41,7 @@ import io.netty.channel.socket.nio.NioSocketChannel;
 import io.netty.handler.codec.serialization.ClassResolvers;
 import io.netty.handler.codec.serialization.ObjectDecoder;
 import io.netty.handler.codec.string.StringEncoder;
+import io.netty.handler.timeout.IdleStateHandler;
 
 @SuppressWarnings("serial")
 public class ChatWindow extends JFrame implements ActionListener, KeyListener, WindowListener {
@@ -153,6 +153,7 @@ public class ChatWindow extends JFrame implements ActionListener, KeyListener, W
 						new ObjectDecoder(ClassResolvers.weakCachingResolver(
 								Packet.class.getClassLoader())));
 				ch.pipeline().addLast("encoder", new StringEncoder());
+				ch.pipeline().addLast(new IdleStateHandler(0, 4, 0));
 				ch.pipeline().addLast("handler",
 						new ChatClientHandler(ChatWindow.this));
 			}

+ 3 - 1
src/main/java/eu/tankernn/chat/common/InfoPacket.java

@@ -6,10 +6,12 @@ import eu.tankernn.chat.server.Client;
 import eu.tankernn.chat.server.Server;
 
 public class InfoPacket implements Packet {
+	
 	/**
 	 * 
 	 */
-	private static final long serialVersionUID = 1L;
+	private static final long serialVersionUID = -7295847853943808703L;
+	
 	public String[] usersOnline;
 	List<String> permissions;
 	public String username, channel;

+ 1 - 1
src/main/java/eu/tankernn/chat/common/MessagePacket.java

@@ -13,7 +13,7 @@ public class MessagePacket implements Packet {
 	/**
 	 * 
 	 */
-	private static final long serialVersionUID = 1L;
+	private static final long serialVersionUID = 91062579797334511L;
 
 	public enum MessageType {
 		PM, NORMAL, WARNING, ERROR, COMMAND, INFO

+ 4 - 1
src/main/java/eu/tankernn/chat/server/ChatServerHandler.java

@@ -8,6 +8,8 @@ public class ChatServerHandler extends ChannelInboundHandlerAdapter {
 	
 	@Override
 	public void channelRead(ChannelHandlerContext ctx, Object msg) {
+		if (((String) msg).equals("/ping"))
+			return;
 		if (c != null) {
 			// Existing client
 			c.handleMessage((String) msg);
@@ -24,7 +26,8 @@ public class ChatServerHandler extends ChannelInboundHandlerAdapter {
 	
 	@Override
 	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-		c.disconnect();
+		c.cleanUp();
+		Server.cleanUp();
 	}
 	
 	@Override

+ 17 - 12
src/main/java/eu/tankernn/chat/server/Client.java

@@ -4,6 +4,7 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
 import java.net.InetSocketAddress;
+import java.nio.channels.ClosedChannelException;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
@@ -87,23 +88,25 @@ public class Client {
 		return true;
 	}
 	
-	public void disconnect(boolean output) {
+	public void disconnect() {
 		if (!isConnected()) // Already disconnected
 			return;
 		
-		timer.cancel();
 		c.close();
-		Server.cleanUp();
+	}
+	
+	public void cleanUp() {
+		cleanUp(true);
+	}
+	
+	public void cleanUp(boolean output) {
+		timer.cancel();
 		
 		if (output)
 			Server.wideBroadcast(
 					new MessagePacket(username + " has disconnected."));
 	}
 	
-	public void disconnect() {
-		disconnect(true);
-	}
-	
 	public boolean isConnected() {
 		return c.isActive() && c.isWritable();
 	}
@@ -119,14 +122,14 @@ public class Client {
 	}
 	
 	public void handleMessage(String message) {
-		if (message.startsWith("/")) // Command handling
+		if (message.startsWith("/")) { // Command handling
 			Server.getCommReg().executeCommand(message, this);
-		else // Normal message handling
+		} else // Normal message handling
 		{
 			messLastPeriod++;
 			if (messLastPeriod > 1 && !hasPermission("mod.spam")) {
 				send("No spamming!");
-				disconnect(false);
+				disconnect();
 			} else
 				getPrimaryChannel().broadcast(
 						new MessagePacket(Client.this.username, message));
@@ -140,10 +143,12 @@ public class Client {
 	 */
 	public void send(Packet pack) {
 		ChannelFuture cf = c.writeAndFlush(pack);
-		if (!cf.isSuccess())
+		if (cf.isSuccess())
+			c.writeAndFlush(InfoPacket.of(this));
+		else if (!(cf.cause() instanceof ClosedChannelException))
 			Server.getLogger().log(Level.SEVERE, "Error sending packet.",
 					cf.cause());
-		c.writeAndFlush(InfoPacket.of(this));
+		
 	}
 	
 	public void send(String message) {

+ 1 - 1
src/main/java/eu/tankernn/chat/server/CommandRegistry.java

@@ -20,7 +20,7 @@ public class CommandRegistry  {
 	private static final Logger LOG = Logger.getLogger(CommandRegistry.class.getName());
 	private Map<String, Command> commands = new HashMap<>();
 	
-	private static final String COMMAND_PACKAGE = "server.command";
+	private static final String COMMAND_PACKAGE = "eu.tankernn.chat.server.command";
 	
 	public CommandRegistry() {
 		Reflections reflections = new Reflections(COMMAND_PACKAGE);

+ 20 - 4
src/main/java/eu/tankernn/chat/server/LocalClient.java

@@ -1,26 +1,42 @@
 package eu.tankernn.chat.server;
 
 import java.io.BufferedReader;
+import java.io.IOException;
 import java.io.InputStreamReader;
 import java.util.Arrays;
 
 import eu.tankernn.chat.common.MessagePacket;
 import eu.tankernn.chat.common.Packet;
 
-public class LocalClient extends Client {
+public class LocalClient extends Client implements Runnable {
+	
+	Thread inputThread;
 	
 	/**
 	 * Constructor for local client, the server, with full permissions
 	 */
 	public LocalClient() {
-		super("SERVER", Arrays.asList(new String[] {"*"}), new BufferedReader(new InputStreamReader(System.in)), null);
+		super("SERVER", Arrays.asList(new String[] {"*"}), null, null);
+		inputThread = new Thread(this);
+		inputThread.start();
 	}
 	
 	@Override
-	public void disconnect(boolean bool) {
-		disconnect(false);
+	public void run() {
+		BufferedReader reader = new BufferedReader(
+				new InputStreamReader(System.in));
+		while (!Thread.interrupted()) {
+			try {
+				handleMessage(reader.readLine());
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
 	}
 	
+	@Override
+	public void disconnect() {}
+	
 	@Override
 	public void send(Packet pack) {
 		if (pack instanceof MessagePacket)

+ 4 - 5
src/main/java/eu/tankernn/chat/server/Server.java

@@ -13,20 +13,17 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import eu.tankernn.chat.common.MessagePacket;
-import eu.tankernn.chat.common.Packet;
 import io.netty.bootstrap.ServerBootstrap;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelOption;
 import io.netty.channel.EventLoopGroup;
-import io.netty.channel.ServerChannel;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.channel.socket.nio.NioServerSocketChannel;
-import io.netty.handler.codec.serialization.ClassResolvers;
-import io.netty.handler.codec.serialization.ObjectDecoder;
 import io.netty.handler.codec.serialization.ObjectEncoder;
 import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.timeout.ReadTimeoutHandler;
 
 public class Server {
 	private static Thread clientListener;
@@ -107,6 +104,8 @@ public class Server {
 									new StringDecoder());
 							ch.pipeline().addLast("encoder",
 									new ObjectEncoder());
+							ch.pipeline().addLast("timeouthandler",
+									new ReadTimeoutHandler(5));
 							ch.pipeline().addLast("handler",
 									new ChatServerHandler());
 						}
@@ -122,7 +121,7 @@ public class Server {
 			// shut down your server.
 			f.channel().closeFuture().sync();
 		} catch (InterruptedException e) {
-			e.printStackTrace();
+			// No need to handle, just shut down
 		} finally {
 			workerGroup.shutdownGracefully();
 			bossGroup.shutdownGracefully();

+ 1 - 1
src/main/java/eu/tankernn/chat/server/command/Kick.java

@@ -15,7 +15,7 @@ public class Kick implements Command {
 		Optional<Client> maybeVictim = Server.getUserByName(args[0]);
 
 		try {
-			maybeVictim.orElseThrow(NullPointerException::new).disconnect(false);
+			maybeVictim.orElseThrow(NullPointerException::new).disconnect();
 		} catch (NullPointerException ex) {
 			caller.send(new MessagePacket("No user called " + args[0] + "!", MessageType.ERROR));
 		}