diff --git a/src/main/java/org/toop/Main.java b/src/main/java/org/toop/Main.java index 8e7c4aa..22b074e 100644 --- a/src/main/java/org/toop/Main.java +++ b/src/main/java/org/toop/Main.java @@ -4,10 +4,10 @@ import org.toop.eventbus.Events; import org.toop.eventbus.GlobalEventBus; import org.toop.server.Server; import org.toop.server.backend.Testsss; +import org.toop.server.backend.TcpServer; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; -import org.toop.server.backend.local.TcpServer; public class Main { private static final Logger logger = LogManager.getLogger(Main.class); @@ -21,8 +21,8 @@ public class Main { TcpServer server = new TcpServer(5001); Thread serverThread = new Thread(server); serverThread.start(); - Server.start("REMOTE", "127.0.0.1", "5001"); -// Testsss.start(""); // Used for testing server. + Server.start("127.0.0.1", "5001"); + // Testsss.start(""); // Used for testing server. Window.start(""); } @@ -32,10 +32,6 @@ public class Main { */ private static boolean initEvents() { try { - GlobalEventBus.subscribeAndRegister(Events.ServerEvents.OnChangingServerBackend.class, - event -> - logger.info("Changing server backend state to {}", event.backend()) - ); GlobalEventBus.subscribeAndRegister(Events.ServerEvents.OnChangingServerIp.class, event -> diff --git a/src/main/java/org/toop/eventbus/Events.java b/src/main/java/org/toop/eventbus/Events.java index d619bd4..30168d0 100644 --- a/src/main/java/org/toop/eventbus/Events.java +++ b/src/main/java/org/toop/eventbus/Events.java @@ -1,13 +1,77 @@ package org.toop.eventbus; import org.toop.server.Server; -import org.toop.server.ServerCommand; + +import java.lang.reflect.Constructor; +import java.util.Arrays; /** * Events that are used in the GlobalEventBus class. */ public class Events implements IEvents { + /** + * + * WIP, DO NOT USE! + * + * @param eventName + * @param args + * @return + * @throws Exception + */ + public static Object get(String eventName, Object... args) throws Exception { + Class clazz = Class.forName("org.toop.eventbus.Events$ServerEvents$" + eventName); + Class[] paramTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new); + Constructor constructor = clazz.getConstructor(paramTypes); + return constructor.newInstance(args); + } + + /** + * + * WIP, DO NOT USE! + * + * @param eventCategory + * @param eventName + * @param args + * @return + * @throws Exception + */ + public static Object get(String eventCategory, String eventName, Object... args) throws Exception { + Class clazz = Class.forName("org.toop.eventbus.Events$" + eventCategory + "$" + eventName); + Class[] paramTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new); + Constructor constructor = clazz.getConstructor(paramTypes); + return constructor.newInstance(args); + } + + /** + * + * WIP, DO NOT USE! + * + * @param eventName + * @param args + * @return + * @throws Exception + */ + public static Object get2(String eventName, Object... args) throws Exception { + // Fully qualified class name + String className = "org.toop.server.backend.Events$ServerEvents$" + eventName; + + // Load the class + Class clazz = Class.forName(className); + + // Build array of argument types + Class[] paramTypes = new Class[args.length]; + for (int i = 0; i < args.length; i++) { + paramTypes[i] = args[i].getClass(); + } + + // Get the constructor + Constructor constructor = clazz.getConstructor(paramTypes); + + // Create a new instance + return constructor.newInstance(args); + } + public static class ServerEvents { /** @@ -20,33 +84,46 @@ public class Events implements IEvents { */ public record OnCommand(org.toop.server.ServerCommand command, String[] args, String result) {} + /** + * Triggers when the server client receives a message. + */ public record ReceivedMessage(String message) {} - /** - * Triggers on changing the server backend. - */ - public record OnChangingServerBackend(Server.ServerBackend backend) {} - - /** - * Triggers changing the server ip. - */ - public record changeServerIp(String ip) {} - /** * Triggers on changing the server ip. */ public record OnChangingServerIp(String ip) {} - /** - * Triggers changing the server port. - */ - public record changeServerPort(String port) {} - /** * Triggers on changing the server port. */ public record OnChangingServerPort(String port) {} + /** + * Triggers reconnecting to previous address. + */ + public record Reconnect() {} + + /** + * Triggers changing connection to a new address. + */ + public record ChangeConnection(String ip, String port) { } + } + public static class EventBusEvents { + + } + + public static class WindowEvents { + + } + + public static class TttEvents { + + } + + public static class AiTttEvents { + + } } diff --git a/src/main/java/org/toop/server/Server.java b/src/main/java/org/toop/server/Server.java index ce72013..71b7e18 100644 --- a/src/main/java/org/toop/server/Server.java +++ b/src/main/java/org/toop/server/Server.java @@ -1,17 +1,14 @@ package org.toop.server; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.toop.Main; import org.toop.eventbus.Events; import org.toop.eventbus.GlobalEventBus; -import org.toop.server.backend.*; -import org.toop.server.backend.local.Local; -import org.toop.server.backend.remote.Remote; -import org.toop.server.backend.remote.TcpClient; +import org.toop.server.backend.TcpClient; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.IOException; -import java.net.UnknownHostException; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -26,46 +23,22 @@ public class Server extends Thread { String ip; String port; - IBackend backend; - BlockingQueue commandQueue; - // TODO Reconnect and keep trying to connect. + BlockingQueue commandQueue; // TODO, add a way to close it, for when reconnecting. + TcpClient tcpClient; + volatile boolean running = false; + Thread tcpIn; + Thread tcpOut; - public Server(String set_backend, String set_ip, String set_port) { + public Server(String set_ip, String set_port) { ip = set_ip; port = set_port; - this.setBackend(set_backend); this.initEvents(); this.commandQueue = new LinkedBlockingQueue<>(); - } - - public IBackend getBackend() { - return backend; - } - - /** - * @param backend The backend to change to. - */ - public void setBackend(ServerBackend backend) { - if (backend == ServerBackend.LOCAL) { - this.backend = new Local(); - GlobalEventBus.post(new Events.ServerEvents.OnChangingServerBackend(ServerBackend.LOCAL)); + try { + this.tcpClient = new TcpClient(this.getIp(), Integer.parseInt(this.getPort())); + } catch (IOException e) { + e.printStackTrace(); } - else { - this.backend = new Remote(); - GlobalEventBus.post(new Events.ServerEvents.OnChangingServerBackend(ServerBackend.REMOTE)); - } - } - - public void setBackend(String backend) { - if (backend.equalsIgnoreCase("REMOTE")) { - this.backend = new Remote(); - GlobalEventBus.post(new Events.ServerEvents.OnChangingServerBackend(ServerBackend.REMOTE)); - } - else { - this.backend = new Local(); - GlobalEventBus.post(new Events.ServerEvents.OnChangingServerBackend(ServerBackend.LOCAL)); - } - } public String getIp() { @@ -76,8 +49,10 @@ public class Server extends Thread { * @param ip The ip to change to. */ public void setIp(String ip) { + this.ip = ip; GlobalEventBus.post(new Events.ServerEvents.OnChangingServerIp(ip)); + } public String getPort() { @@ -89,8 +64,10 @@ public class Server extends Thread { * @param port The port to change to. */ public void setPort(String port) { + this.port = port; GlobalEventBus.post(new Events.ServerEvents.OnChangingServerPort(port)); + } /** @@ -101,11 +78,17 @@ public class Server extends Thread { * @param args The arguments for the command. */ private void sendCommandByString(String command, String... args) { + if (!ServerCommand.isValid(command)) { logger.error("Invalid command: {}", command); return; } + if (!running) { + logger.warn("Server has been stopped"); + return; + } + for (int i = 0; i < args.length; i++) { args[i] = args[i].trim(); if (args[i].isEmpty()) { @@ -125,42 +108,49 @@ public class Server extends Thread { @Override public String toString() { + return String.format( - "Server {ip: \"%s\", port: \"%s\", backend: \"%s\"}", - ip, port, backend + "Server {ip: \"%s\", port: \"%s\"}", + ip, port ); + } private void initEvents() { + GlobalEventBus.subscribeAndRegister(Events.ServerEvents.command.class, event -> this.sendCommandByString(event.command(), event.args())); - GlobalEventBus.subscribeAndRegister(Events.ServerEvents.changeServerIp.class, event - -> this.setIp(event.ip())); - GlobalEventBus.subscribeAndRegister(Events.ServerEvents.changeServerPort.class, event - -> this.setPort(event.port())); + GlobalEventBus.subscribeAndRegister(Events.ServerEvents.Reconnect.class, event + -> { + try { + this.reconnect(); // TODO: Terrible error handling and code. Needs cleanup. + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + GlobalEventBus.subscribeAndRegister(Events.ServerEvents.ChangeConnection.class, event + -> { + try { + this.connect(event.ip(), event.port()); // TODO: Terrible error handling and code. Needs cleanup. + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + } - /** - * DO NOT USE, USE START INSTEAD. - */ - public void run() { - try { - TcpClient client = new TcpClient(this.getIp(), Integer.parseInt(this.getPort())); // TODO Parsing to int is unsafe - theRemoteServerTimeline(client); - } catch (UnknownHostException | InterruptedException e) { // TODO Better error handling. - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + private void connection() throws InterruptedException { // TODO: Rename - private void theRemoteServerTimeline(TcpClient client) throws InterruptedException { // TODO: Rename sleep(1000); // Just wait, because why not - new Thread(() -> { + this.tcpIn = new Thread(() -> { try { - while (true) { - String received = client.readLine(); // blocks until a line is available + while (this.running) { + String received = this.tcpClient.readLine(); // blocks until a line is available if (received != null) { logger.info("Received: '{}'", received); GlobalEventBus.post(new Events.ServerEvents.ReceivedMessage(received)); @@ -170,37 +160,124 @@ public class Server extends Thread { } } catch (IOException e) { logger.error("Error reading from server", e); + try { + this.tcpClient.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } } - }).start(); + }); - new Thread(() -> { + this.tcpOut = new Thread(() -> { try { - while (true) { + while (this.running) { String command = commandQueue.take(); // blocks until a command is available - client.sendMessage(command); + this.tcpClient.sendMessage(command); logger.info("Sent command: '{}'", command); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (IOException e) { + try { + tcpClient.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } throw new RuntimeException(e); } - }).start(); + }); + + this.tcpIn.start(); + this.tcpOut.start(); + + } + + /** + * + * Connect to a new server. + * + * @param ip The ip to connect to. + * @param port The port to connect to. + * @throws IOException wip + * @throws InterruptedException wip + */ + public void connect(String ip, String port) throws IOException, InterruptedException { + + if (running) { + this.close(); + } + + this.ip = ip; + this.port = port; + + running = true; + + this.tcpClient = new TcpClient(ip, Integer.parseInt(port)); + this.connection(); + + } + + /** + * + * Reconnects to previous address. + * + * @throws IOException wip + * @throws InterruptedException wip + */ + public void reconnect() throws IOException, InterruptedException { + this.connect(this.ip, this.port); + } + + /** + * + * Close connection to server. + * + * @throws IOException wip + * @throws InterruptedException wip + */ + public void close() throws IOException, InterruptedException { + + this.commandQueue.clear(); + running = false; + // Thread.currentThread().interrupt(); + + this.tcpClient.closeSocket(); + + this.tcpIn.interrupt(); + this.tcpOut.interrupt(); + this.tcpIn.join(); + this.tcpOut.join(); + + } + + /** + * DO NOT USE, USE START INSTEAD. + */ + public void run() { + + try { + this.reconnect(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } /** * * Starts a server thread. * - * @param backend The backend to use {remote, local} * @param ip The address of the server to contact. * @param port The port of the server. */ - public static void start(String backend, String ip, String port) { + public static void start(String ip, String port) { + try { - new Server(backend, ip, port).start(); + new Server(ip, port).start(); } catch (IllegalArgumentException e) { - new Server("REMOTE", "127.0.0.1", "5001").start(); // TODO: Doesn't do anything. + new Server("127.0.0.1", "5001").start(); // TODO: Doesn't do anything. } } diff --git a/src/main/java/org/toop/server/backend/IBackend.java b/src/main/java/org/toop/server/backend/IBackend.java deleted file mode 100644 index 445948a..0000000 --- a/src/main/java/org/toop/server/backend/IBackend.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.toop.server.backend; - -import org.toop.server.ServerMessage; - -public interface IBackend { - ServerMessage login(String username); -// boolean isValidBackend(String backend); -} - diff --git a/src/main/java/org/toop/server/backend/remote/TcpClient.java b/src/main/java/org/toop/server/backend/TcpClient.java similarity index 89% rename from src/main/java/org/toop/server/backend/remote/TcpClient.java rename to src/main/java/org/toop/server/backend/TcpClient.java index d3e515a..89aba4c 100644 --- a/src/main/java/org/toop/server/backend/remote/TcpClient.java +++ b/src/main/java/org/toop/server/backend/TcpClient.java @@ -1,4 +1,4 @@ -package org.toop.server.backend.remote; +package org.toop.server.backend; import java.io.BufferedReader; import java.io.IOException; @@ -6,7 +6,6 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; -import java.net.UnknownHostException; public class TcpClient { @@ -32,10 +31,14 @@ public class TcpClient { this.out = createOut(); } - private Socket createSocket() throws IOException { + public Socket createSocket() throws IOException { return new Socket(serverAddress, serverPort); } + public void closeSocket() throws IOException { + this.socket.close(); + } + private BufferedReader createIn() throws IOException { return new BufferedReader(new InputStreamReader(this.socket.getInputStream())); } diff --git a/src/main/java/org/toop/server/backend/local/TcpServer.java b/src/main/java/org/toop/server/backend/TcpServer.java similarity index 97% rename from src/main/java/org/toop/server/backend/local/TcpServer.java rename to src/main/java/org/toop/server/backend/TcpServer.java index c0c804d..a07b276 100644 --- a/src/main/java/org/toop/server/backend/local/TcpServer.java +++ b/src/main/java/org/toop/server/backend/TcpServer.java @@ -1,8 +1,9 @@ -package org.toop.server.backend.local; +package org.toop.server.backend; + +import org.toop.Main; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.toop.Main; import java.io.*; import java.net.*; diff --git a/src/main/java/org/toop/server/backend/Testsss.java b/src/main/java/org/toop/server/backend/Testsss.java index 152ccd5..c6e1388 100644 --- a/src/main/java/org/toop/server/backend/Testsss.java +++ b/src/main/java/org/toop/server/backend/Testsss.java @@ -10,8 +10,10 @@ public class Testsss extends Thread { public void run() { while (true) { try { - sleep(1000); + sleep(100); GlobalEventBus.post(new Events.ServerEvents.command("HELP", "TEST")); + sleep(1000); + GlobalEventBus.post(new Events.ServerEvents.ChangeConnection("127.0.0.1", "5001")); } catch (InterruptedException e) { throw new RuntimeException(e); } diff --git a/src/main/java/org/toop/server/backend/local/Local.java b/src/main/java/org/toop/server/backend/local/Local.java deleted file mode 100644 index 8976f08..0000000 --- a/src/main/java/org/toop/server/backend/local/Local.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.toop.server.backend.local; - -import org.toop.server.ServerMessage; -import org.toop.server.backend.IBackend; - -public class Local implements IBackend { - @Override - public ServerMessage login(String username) { - return null; - } - - @Override - public boolean equals(Object o) { - return o instanceof Local; // TODO - } - - @Override - public String toString() { - return "Local"; - } - -} diff --git a/src/main/java/org/toop/server/backend/remote/Remote.java b/src/main/java/org/toop/server/backend/remote/Remote.java deleted file mode 100644 index f172cc2..0000000 --- a/src/main/java/org/toop/server/backend/remote/Remote.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.toop.server.backend.remote; - -import org.toop.server.ServerMessage; -import org.toop.server.backend.IBackend; - -public class Remote implements IBackend { - @Override - public ServerMessage login(String username) { - return null; - } - - @Override - public boolean equals(Object o) { - return o instanceof Remote; // TODO - } - - @Override - public String toString() { - return "Remote"; - } - -}