|
@@ -5,14 +5,11 @@ import java.io.FileNotFoundException;
|
|
import java.io.FileReader;
|
|
import java.io.FileReader;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
import java.io.PrintWriter;
|
|
-import java.net.ServerSocket;
|
|
|
|
-import java.net.Socket;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import java.util.Optional;
|
|
import java.util.Properties;
|
|
import java.util.Properties;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Level;
|
|
-import java.util.logging.LogManager;
|
|
|
|
import java.util.logging.Logger;
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
import eu.tankernn.chat.common.MessagePacket;
|
|
import eu.tankernn.chat.common.MessagePacket;
|
|
@@ -22,11 +19,13 @@ import io.netty.channel.ChannelFuture;
|
|
import io.netty.channel.ChannelInitializer;
|
|
import io.netty.channel.ChannelInitializer;
|
|
import io.netty.channel.ChannelOption;
|
|
import io.netty.channel.ChannelOption;
|
|
import io.netty.channel.EventLoopGroup;
|
|
import io.netty.channel.EventLoopGroup;
|
|
|
|
+import io.netty.channel.ServerChannel;
|
|
import io.netty.channel.nio.NioEventLoopGroup;
|
|
import io.netty.channel.nio.NioEventLoopGroup;
|
|
import io.netty.channel.socket.SocketChannel;
|
|
import io.netty.channel.socket.SocketChannel;
|
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
|
import io.netty.handler.codec.serialization.ClassResolvers;
|
|
import io.netty.handler.codec.serialization.ClassResolvers;
|
|
import io.netty.handler.codec.serialization.ObjectDecoder;
|
|
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.codec.string.StringDecoder;
|
|
|
|
|
|
public class Server {
|
|
public class Server {
|
|
@@ -35,107 +34,88 @@ public class Server {
|
|
private static File propFile = new File("server.properties");
|
|
private static File propFile = new File("server.properties");
|
|
private static int port, maxUsers;
|
|
private static int port, maxUsers;
|
|
private static final String version = "4.0";
|
|
private static final String version = "4.0";
|
|
-
|
|
|
|
|
|
+
|
|
private static ArrayList<BanNote> banNotes = new ArrayList<BanNote>();
|
|
private static ArrayList<BanNote> banNotes = new ArrayList<BanNote>();
|
|
private static ArrayList<Channel> channels = new ArrayList<Channel>();
|
|
private static ArrayList<Channel> channels = new ArrayList<Channel>();
|
|
private static ClientCollection clients;
|
|
private static ClientCollection clients;
|
|
-
|
|
|
|
- private static ServerSocket so;
|
|
|
|
|
|
+
|
|
|
|
+ private static ServerBootstrap bootstrap;
|
|
|
|
+
|
|
private static LocalClient OPClient;
|
|
private static LocalClient OPClient;
|
|
private static final Logger log = Logger.getGlobal();
|
|
private static final Logger log = Logger.getGlobal();
|
|
private static CommandRegistry commandRegistry;
|
|
private static CommandRegistry commandRegistry;
|
|
-
|
|
|
|
|
|
+
|
|
public static void main(String[] arg) {
|
|
public static void main(String[] arg) {
|
|
- try {
|
|
|
|
- LogManager.getLogManager().readConfiguration(Server.class.getResourceAsStream("/logger.properties"));
|
|
|
|
- } catch (SecurityException | IOException e2) {
|
|
|
|
- log.log(Level.SEVERE, e2.getMessage(), e2);
|
|
|
|
- }
|
|
|
|
|
|
+ // try {
|
|
|
|
+ // LogManager.getLogManager().readConfiguration(Server.class.getResourceAsStream("/logger.properties"));
|
|
|
|
+ // } catch (SecurityException | IOException e2) {
|
|
|
|
+ // log.log(Level.SEVERE, e2.getMessage(), e2);
|
|
|
|
+ // }
|
|
log.info("Starting ChatServer version " + version + "...");
|
|
log.info("Starting ChatServer version " + version + "...");
|
|
-
|
|
|
|
|
|
+
|
|
log.fine("Loadning properties file...");
|
|
log.fine("Loadning properties file...");
|
|
try {
|
|
try {
|
|
prop.load(new FileReader(propFile));
|
|
prop.load(new FileReader(propFile));
|
|
} catch (FileNotFoundException e1) {
|
|
} catch (FileNotFoundException e1) {
|
|
try {
|
|
try {
|
|
- prop.load(Server.class.getResourceAsStream("/" + propFile.getName()));
|
|
|
|
|
|
+ prop.load(Server.class
|
|
|
|
+ .getResourceAsStream("/" + propFile.getName()));
|
|
} catch (IOException e) {
|
|
} catch (IOException e) {
|
|
log.log(Level.SEVERE, e.getMessage(), e);
|
|
log.log(Level.SEVERE, e.getMessage(), e);
|
|
}
|
|
}
|
|
} catch (IOException e1) {
|
|
} catch (IOException e1) {
|
|
log.log(Level.SEVERE, e1.getMessage(), e1);
|
|
log.log(Level.SEVERE, e1.getMessage(), e1);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
log.fine("Reading numbers from properties object...");
|
|
log.fine("Reading numbers from properties object...");
|
|
port = Integer.parseInt(prop.getProperty("port"));
|
|
port = Integer.parseInt(prop.getProperty("port"));
|
|
maxUsers = Integer.parseInt(prop.getProperty("maxUsers"));
|
|
maxUsers = Integer.parseInt(prop.getProperty("maxUsers"));
|
|
-
|
|
|
|
- log.fine("Setting up socket...");
|
|
|
|
- try {
|
|
|
|
- so = new ServerSocket(port);
|
|
|
|
- } catch (IOException ex) {
|
|
|
|
- log.log(Level.SEVERE, "Error setting up socket. Server already running?", ex);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+
|
|
clients = new ClientCollection();
|
|
clients = new ClientCollection();
|
|
getChannels().add(new Channel("Main"));
|
|
getChannels().add(new Channel("Main"));
|
|
-
|
|
|
|
|
|
+
|
|
log.fine("Starting commandhandler...");
|
|
log.fine("Starting commandhandler...");
|
|
commandRegistry = new CommandRegistry();
|
|
commandRegistry = new CommandRegistry();
|
|
-
|
|
|
|
|
|
+
|
|
log.fine("Creating virtual local client...");
|
|
log.fine("Creating virtual local client...");
|
|
OPClient = new LocalClient();
|
|
OPClient = new LocalClient();
|
|
-
|
|
|
|
|
|
+
|
|
log.fine("Starting client listener thread...");
|
|
log.fine("Starting client listener thread...");
|
|
clientListener = new Thread(Server::run);
|
|
clientListener = new Thread(Server::run);
|
|
clientListener.start();
|
|
clientListener.start();
|
|
-
|
|
|
|
|
|
+
|
|
log.info("Server started successfully!");
|
|
log.info("Server started successfully!");
|
|
}
|
|
}
|
|
-
|
|
|
|
- static void listenClients() {
|
|
|
|
- while (!so.isClosed()) {
|
|
|
|
- Client newClient = null;
|
|
|
|
- try {
|
|
|
|
- Socket clientSock = so.accept();
|
|
|
|
- clients.cleanUp(); // Free taken names
|
|
|
|
- newClient = new Client(clientSock);
|
|
|
|
- clients.add(newClient);
|
|
|
|
- getChannels().get(0).add(newClient);
|
|
|
|
- wideBroadcast(new MessagePacket(newClient.username + " has connected."));
|
|
|
|
- } catch (IllegalArgumentException ex) {
|
|
|
|
-
|
|
|
|
- } catch (ArrayIndexOutOfBoundsException ex) {
|
|
|
|
- newClient.send(new MessagePacket("Server full!"));
|
|
|
|
- newClient.disconnect(false);
|
|
|
|
- } catch (IOException ex) {
|
|
|
|
- if (so.isClosed())
|
|
|
|
- return;
|
|
|
|
- } catch (Exception ex) {
|
|
|
|
- log.log(Level.WARNING, "Could not get new client!", ex);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ public static void addClient(Client c) {
|
|
|
|
+ clients.add(c);
|
|
|
|
+ getChannels().get(0).add(c);
|
|
|
|
+ wideBroadcast(new MessagePacket(c.username + " has connected."));
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
private static void run() {
|
|
private static void run() {
|
|
EventLoopGroup bossGroup = new NioEventLoopGroup();
|
|
EventLoopGroup bossGroup = new NioEventLoopGroup();
|
|
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
|
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
|
try {
|
|
try {
|
|
- ServerBootstrap b = new ServerBootstrap();
|
|
|
|
- b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
|
|
|
|
|
|
+ bootstrap = new ServerBootstrap();
|
|
|
|
+ bootstrap.group(bossGroup, workerGroup)
|
|
|
|
+ .channel(NioServerSocketChannel.class)
|
|
.childHandler(new ChannelInitializer<SocketChannel>() {
|
|
.childHandler(new ChannelInitializer<SocketChannel>() {
|
|
@Override
|
|
@Override
|
|
public void initChannel(SocketChannel ch) throws Exception {
|
|
public void initChannel(SocketChannel ch) throws Exception {
|
|
- ch.pipeline().addLast("decoder", new StringDecoder());
|
|
|
|
- ch.pipeline().addLast("encoder", new ObjectDecoder(ClassResolvers.weakCachingResolver(Packet.class.getClassLoader())));
|
|
|
|
- ch.pipeline().addLast("handler", new ChatServerHandler());
|
|
|
|
|
|
+ ch.pipeline().addLast("decoder",
|
|
|
|
+ new StringDecoder());
|
|
|
|
+ ch.pipeline().addLast("encoder",
|
|
|
|
+ new ObjectEncoder());
|
|
|
|
+ ch.pipeline().addLast("handler",
|
|
|
|
+ new ChatServerHandler());
|
|
}
|
|
}
|
|
- }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
|
|
|
|
-
|
|
|
|
|
|
+ }).option(ChannelOption.SO_BACKLOG, 128)
|
|
|
|
+ .childOption(ChannelOption.SO_KEEPALIVE, true);
|
|
|
|
+
|
|
// Bind and start to accept incoming connections.
|
|
// Bind and start to accept incoming connections.
|
|
- ChannelFuture f = b.bind(port).sync();
|
|
|
|
-
|
|
|
|
|
|
+ ChannelFuture f = bootstrap.bind(port).sync();
|
|
|
|
+
|
|
// Wait until the server socket is closed.
|
|
// Wait until the server socket is closed.
|
|
// In this example, this does not happen, but you can do that to
|
|
// In this example, this does not happen, but you can do that to
|
|
// gracefully
|
|
// gracefully
|
|
@@ -148,31 +128,32 @@ public class Server {
|
|
bossGroup.shutdownGracefully();
|
|
bossGroup.shutdownGracefully();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static Optional<Channel> getChannelByName(String name) throws NullPointerException {
|
|
public static Optional<Channel> getChannelByName(String name) throws NullPointerException {
|
|
- return getChannels().stream().filter(c -> c.name.equals(name)).findFirst();
|
|
|
|
|
|
+ return getChannels().stream().filter(c -> c.name.equals(name))
|
|
|
|
+ .findFirst();
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static void wideBroadcast(MessagePacket mess) {
|
|
public static void wideBroadcast(MessagePacket mess) {
|
|
getClients().broadcast(mess);
|
|
getClients().broadcast(mess);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static String[] getUsersOnline() {
|
|
public static String[] getUsersOnline() {
|
|
return getClients().getUsernameArray();
|
|
return getClients().getUsernameArray();
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static String listClients(CharSequence c) {
|
|
public static String listClients(CharSequence c) {
|
|
return getClients().listClients(c);
|
|
return getClients().listClients(c);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static Optional<Client> getUserByName(String username) {
|
|
public static Optional<Client> getUserByName(String username) {
|
|
return getClients().getClientByName(username);
|
|
return getClients().getClientByName(username);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static void ban(BanNote ban) {
|
|
public static void ban(BanNote ban) {
|
|
banNotes.add(ban);
|
|
banNotes.add(ban);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Removes disconnected clients from all collections on the server.
|
|
* Removes disconnected clients from all collections on the server.
|
|
*/
|
|
*/
|
|
@@ -180,56 +161,51 @@ public class Server {
|
|
getClients().cleanUp();
|
|
getClients().cleanUp();
|
|
getChannels().forEach(c -> c.cleanUp());
|
|
getChannels().forEach(c -> c.cleanUp());
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Disconnects all users and closes log and socket.
|
|
* Disconnects all users and closes log and socket.
|
|
*/
|
|
*/
|
|
public static void exit() {
|
|
public static void exit() {
|
|
wideBroadcast(new MessagePacket("Shutting down server!"));
|
|
wideBroadcast(new MessagePacket("Shutting down server!"));
|
|
-
|
|
|
|
- try {
|
|
|
|
- so.close();
|
|
|
|
- } catch (IOException e) {
|
|
|
|
- e.printStackTrace();
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
clientListener.interrupt();
|
|
clientListener.interrupt();
|
|
-
|
|
|
|
|
|
+
|
|
clients.disconnectAll();
|
|
clients.disconnectAll();
|
|
getLocalClient().disconnect();
|
|
getLocalClient().disconnect();
|
|
-
|
|
|
|
|
|
+
|
|
try {
|
|
try {
|
|
prop.store(new PrintWriter(propFile), "ChatServer config file");
|
|
prop.store(new PrintWriter(propFile), "ChatServer config file");
|
|
} catch (IOException e1) {
|
|
} catch (IOException e1) {
|
|
e1.printStackTrace();
|
|
e1.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static int getMaxUsers() {
|
|
public static int getMaxUsers() {
|
|
return maxUsers;
|
|
return maxUsers;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static LocalClient getLocalClient() {
|
|
public static LocalClient getLocalClient() {
|
|
return OPClient;
|
|
return OPClient;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static Logger getLogger() {
|
|
public static Logger getLogger() {
|
|
return log;
|
|
return log;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static ArrayList<Channel> getChannels() {
|
|
public static ArrayList<Channel> getChannels() {
|
|
return channels;
|
|
return channels;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static ClientCollection getClients() {
|
|
public static ClientCollection getClients() {
|
|
return clients;
|
|
return clients;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static CommandRegistry getCommReg() {
|
|
public static CommandRegistry getCommReg() {
|
|
return commandRegistry;
|
|
return commandRegistry;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public static List<BanNote> getBanned() {
|
|
public static List<BanNote> getBanned() {
|
|
return banNotes;
|
|
return banNotes;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
}
|
|
}
|