├── .gitignore ├── README.md ├── messaging-client ├── pom.xml └── src │ └── main │ └── java │ └── me │ └── hp888 │ └── messenger │ ├── MessengerClient.java │ ├── api │ ├── callback │ │ ├── Callback.java │ │ └── CallbackManager.java │ ├── client │ │ └── Client.java │ └── packet │ │ ├── CallbackPacket.java │ │ ├── Packet.java │ │ ├── PacketHandler.java │ │ └── PacketHandlerManager.java │ ├── connection │ └── SocketConnection.java │ ├── packet │ └── HeartbeatPacket.java │ ├── thread │ └── PacketReaderThread.java │ └── util │ └── SerializeUtil.java ├── messaging-server ├── pom.xml └── src │ └── main │ └── java │ └── me │ └── hp888 │ └── messenger │ ├── Bootstrap.java │ ├── MessengerServer.java │ ├── client │ ├── Client.java │ └── ClientManager.java │ ├── thread │ ├── PacketReaderThread.java │ ├── PacketWriterThread.java │ └── ServerShutdownThread.java │ └── util │ └── ThreadUtil.java ├── messenger-plugin ├── pom.xml └── src │ └── main │ ├── java │ └── me │ │ └── hp888 │ │ └── messenger │ │ ├── bukkit │ │ └── BukkitMessengerPlugin.java │ │ ├── bungee │ │ └── BungeeMessengerPlugin.java │ │ ├── shared │ │ ├── Messenger.java │ │ ├── MessengerPlugin.java │ │ └── config │ │ │ └── Configuration.java │ │ └── velocity │ │ └── VelocityMessengerPlugin.java │ └── resources │ ├── bungee.yml │ ├── config.json │ └── plugin.yml └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | # Compiled class file 4 | *.class 5 | 6 | # Log file 7 | *.log 8 | 9 | # BlueJ files 10 | *.ctxt 11 | 12 | # Mobile Tools for Java (J2ME) 13 | .mtj.tmp/ 14 | 15 | # Package Files # 16 | *.jar 17 | *.war 18 | *.nar 19 | *.ear 20 | *.zip 21 | *.tar.gz 22 | *.rar 23 | *.iml 24 | 25 | target/ 26 | 27 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 28 | hs_err_pid* 29 | 30 | .idea/* 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # messaging-system 2 | 3 | Packet-based messaging system. 4 | 5 | # Examples 6 | 7 | **How to run server?** 8 | 9 | You can specify port and host in java arguments for example: 10 | java -Dhost=0.0.0.0 -Dport=9999 -jar messaging-server-1.0-SNAPSHOT.jar 11 | 12 | or just run application: 13 | java -jar messaging-server-1.0-SNAPSHOT.jar 14 | 15 | # Using as API 16 | 17 | Add this code to your pom.xml file. 18 | 19 | ```xml 20 | 21 | 22 | safemc-repository 23 | https://safemc.pl/repository/releases 24 | 25 | 26 | ``` 27 | 28 | And if you want to create your own MessengerClient implementation: 29 | 30 | ```xml 31 | 32 | 33 | me.hp888 34 | messaging-client 35 | 1.1-SNAPSHOT 36 | 37 | 38 | ``` 39 | 40 | or if you want to use our plugin for bukkit/velocity/bungee: 41 | 42 | ```xml 43 | 44 | 45 | me.hp888 46 | messenger-plugin 47 | 1.1-SNAPSHOT 48 | 49 | 50 | ``` 51 | 52 | **Example packet** 53 | 54 | ```java 55 | public final class ExamplePacket implements Packet { 56 | 57 | private String text; 58 | 59 | public ExamplePacket() { 60 | } 61 | 62 | public ExamplePacket(String text) { 63 | this.text = text; 64 | } 65 | 66 | public String getText() { 67 | return text; 68 | } 69 | 70 | public void setText(String text) { 71 | this.text = text; 72 | } 73 | 74 | @Override 75 | public void processPacket(PacketHandler handler) { 76 | if (!(handler instanceof ExamplePacketHandler)) { 77 | return; 78 | } 79 | 80 | ((ExamplePacketHandler) handler).handlePacket(this); 81 | } 82 | 83 | } 84 | ``` 85 | 86 | **Example packet handler** 87 | 88 | ```java 89 | public final class ExamplePacketHandler implements PacketHandler { 90 | 91 | private final Client client; 92 | 93 | public ExamplePacketHandler(Client client) { 94 | this.client = client; 95 | } 96 | 97 | public void handlePacket(ExamplePacket packet) { 98 | System.out.println("Message: " + packet.getText()); 99 | } 100 | 101 | public void handlePacket(ExampleCallbackPacket packet) { 102 | if (packet.isResponse()) { 103 | return; 104 | } 105 | 106 | packet.setText("test"); 107 | packet.setResponse(); 108 | 109 | client.sendPacket(packet); // sending packet back to handle callback 110 | } 111 | 112 | } 113 | ``` 114 | 115 | **Example CallbackPacket** 116 | 117 | ```java 118 | public final class ExampleCallbackPacket extends CallbackPacket { 119 | 120 | private String text; 121 | 122 | public ExampleCallbackPacket() { 123 | } 124 | 125 | public ExampleCallbackPacket(String text) { 126 | this.text = text; 127 | } 128 | 129 | public String getText() { 130 | return text; 131 | } 132 | 133 | public void setText(String text) { 134 | this.text = text; 135 | } 136 | 137 | @Override 138 | public void processPacket(PacketHandler handler) { 139 | if (!(handler instanceof ExamplePacketHandler)) { 140 | return; 141 | } 142 | 143 | ((ExamplePacketHandler) handler).handlePacket(this); 144 | } 145 | 146 | } 147 | ``` 148 | 149 | **Example connection to server** 150 | 151 | ```java 152 | final Client client = new MessengerClient(); 153 | client.connect(new InetSocketAddress("127.0.0.1", 9999)); 154 | ``` 155 | 156 | **Subscribing packets** 157 | 158 | How it works? 159 | Only subscribed packets can be fully readed by the client, so if you subscribe ExamplePacket and this packet will be sent by any client Packet#processPacket method will be called. 160 | 161 | ```java 162 | client.subscribePackets(ExamplePacket.class.getName()); 163 | ``` 164 | 165 | **Adding packet handlers** 166 | 167 | ```java 168 | client.addPacketHandler(new ExamplePacketHandler()); 169 | ``` 170 | 171 | **Removing packet handlers** 172 | 173 | ```java 174 | client.removePacketHandler(ExamplePacketHandler.class); 175 | ``` 176 | 177 | **Sending packets** 178 | 179 | ```java 180 | client.sendPacket(new ExamplePacket("test")); 181 | ``` 182 | 183 | **Sending packets with callback** 184 | ```java 185 | client.sendPacket(new ExampleCallbackPacket(), new Callback() { 186 | @Override 187 | public void done(ExampleCallbackPacket packet) { 188 | System.out.println("Response message: " + packet.getText()); 189 | } 190 | 191 | @Override 192 | public void error(String message) { 193 | System.out.println("Error message: " + message); 194 | } 195 | }); 196 | ``` 197 | -------------------------------------------------------------------------------- /messaging-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | messaging-system 7 | me.hp888 8 | 1.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | messaging-client 13 | 14 | 15 | 1.8 16 | 1.8 17 | 18 | 19 | 20 | 21 | de.ruedigermoeller 22 | fst 23 | 2.57 24 | compile 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/MessengerClient.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger; 2 | 3 | import lombok.Getter; 4 | import me.hp888.messenger.api.callback.Callback; 5 | import me.hp888.messenger.api.callback.CallbackManager; 6 | import me.hp888.messenger.api.client.Client; 7 | import me.hp888.messenger.api.packet.Packet; 8 | import me.hp888.messenger.api.packet.PacketHandler; 9 | import me.hp888.messenger.api.packet.PacketHandlerManager; 10 | import me.hp888.messenger.connection.SocketConnection; 11 | import me.hp888.messenger.packet.HeartbeatPacket; 12 | import me.hp888.messenger.thread.PacketReaderThread; 13 | import java.io.IOException; 14 | import java.net.InetSocketAddress; 15 | import java.net.Socket; 16 | import java.util.Collection; 17 | import java.util.Objects; 18 | import java.util.concurrent.ExecutorService; 19 | import java.util.concurrent.Executors; 20 | import java.util.concurrent.TimeUnit; 21 | import java.util.logging.Level; 22 | import java.util.logging.Logger; 23 | 24 | /** 25 | * @author hp888 on 07.11.2020. 26 | */ 27 | 28 | public final class MessengerClient implements Client { 29 | 30 | private static final ExecutorService PACKET_SEND_EXECUTOR = Executors.newSingleThreadExecutor(); 31 | 32 | private final PacketHandlerManager packetHandlers = new PacketHandlerManager(); 33 | private final CallbackManager callbacks = new CallbackManager(); 34 | 35 | @Getter 36 | private final ExecutorService packetHandleExecutor; 37 | 38 | public MessengerClient() { 39 | this(Runtime.getRuntime().availableProcessors() * 2); 40 | } 41 | 42 | public MessengerClient(int handlerPoolSize) { 43 | packetHandleExecutor = Executors.newFixedThreadPool(handlerPoolSize); 44 | } 45 | 46 | @Getter 47 | private SocketConnection connection; 48 | 49 | private boolean startedKeepAliveTask; 50 | 51 | @Override 52 | public void disconnect() throws IOException { 53 | if (Objects.isNull(connection) || !connection.isAlive()) { 54 | return; 55 | } 56 | 57 | connection.getSocket().close(); 58 | } 59 | 60 | @Override 61 | public void connect(InetSocketAddress address) throws IOException { 62 | final Socket socket = new Socket(); 63 | socket.setTcpNoDelay(true); 64 | socket.connect(address, 5000); 65 | 66 | connection = new SocketConnection(socket); 67 | new PacketReaderThread(this) 68 | .start(); 69 | 70 | if (startedKeepAliveTask) { 71 | return; 72 | } 73 | 74 | startedKeepAliveTask = true; 75 | 76 | final Packet heartbeatPacket = new HeartbeatPacket(); 77 | Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> sendPacket(heartbeatPacket), 1L, 1L, TimeUnit.SECONDS); 78 | } 79 | 80 | @Override 81 | public void unsubscribePackets() { 82 | packetHandlers.unsubscribePackets(); 83 | } 84 | 85 | @Override 86 | public void subscribePackets(String... classNames) { 87 | packetHandlers.subscribePackets(classNames); 88 | } 89 | 90 | @Override 91 | public boolean isPacketSubscribed(String name) { 92 | return packetHandlers.isPacketSubscribed(name); 93 | } 94 | 95 | @Override 96 | public Collection getPacketHandlers() { 97 | return packetHandlers.getPacketHandlers(); 98 | } 99 | 100 | @Override 101 | public void addPacketHandler(PacketHandler handler) { 102 | packetHandlers.addPacketHandler(handler); 103 | } 104 | 105 | @Override 106 | public void removePacketHandler(Class handlerClass) { 107 | packetHandlers.removePacketHandler(handlerClass); 108 | } 109 | 110 | @Override 111 | public Callback getCallback(long id) { 112 | return callbacks.getCallback(id); 113 | } 114 | 115 | @Override 116 | public void sendPacket(Packet packet) { 117 | if (!checkConnection()) { 118 | return; 119 | } 120 | 121 | PACKET_SEND_EXECUTOR.execute(() -> { 122 | try { 123 | connection.sendPacket(packet, null); 124 | } catch (IOException ex) { 125 | Logger.getLogger(MessengerClient.class.getSimpleName()) 126 | .log(Level.SEVERE, "Cannot send packet " + packet.getClass().getSimpleName(), ex); 127 | 128 | try { 129 | disconnect(); 130 | } catch (IOException ignored) {} 131 | } 132 | }); 133 | } 134 | 135 | @Override 136 | public void sendPacket(Packet packet, Callback callback) { 137 | if (Objects.isNull(callback)) { 138 | sendPacket(packet); 139 | return; 140 | } 141 | 142 | if (!checkConnection()) { 143 | return; 144 | } 145 | 146 | PACKET_SEND_EXECUTOR.execute(() -> { 147 | try { 148 | connection.sendPacket(packet, callbacks.addCallback(callback)); 149 | } catch (IOException ex) { 150 | Logger.getLogger(MessengerClient.class.getSimpleName()) 151 | .log(Level.SEVERE, "Cannot send packet " + packet.getClass().getSimpleName(), ex); 152 | 153 | try { 154 | disconnect(); 155 | } catch (IOException ignored) {} 156 | } 157 | }); 158 | } 159 | 160 | private boolean checkConnection() { 161 | if (Objects.isNull(connection) || !connection.isAlive()) { 162 | Logger.getLogger(getClass().getSimpleName()) 163 | .warning("Cannot send packet when client is not connected!"); 164 | 165 | return false; 166 | } 167 | 168 | return true; 169 | } 170 | 171 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/api/callback/Callback.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.api.callback; 2 | 3 | import me.hp888.messenger.api.packet.Packet; 4 | 5 | /** 6 | * @author hp888 on 07.11.2020. 7 | */ 8 | 9 | public interface Callback { 10 | 11 | void done(T packet); 12 | 13 | void error(String message); 14 | 15 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/api/callback/CallbackManager.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.api.callback; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.concurrent.ThreadLocalRandom; 6 | 7 | /** 8 | * @author hp888 on 07.11.2020. 9 | */ 10 | 11 | public final class CallbackManager { 12 | 13 | private final Map> callbackMap = new HashMap<>(); 14 | 15 | public long addCallback(Callback callback) { 16 | long id; 17 | 18 | do { 19 | id = ThreadLocalRandom.current().nextLong(Long.MIN_VALUE, Long.MAX_VALUE); 20 | } while (callbackMap.containsKey(id)); 21 | 22 | callbackMap.put(id, callback); 23 | return id; 24 | } 25 | 26 | public Callback getCallback(long id) { 27 | return callbackMap.remove(id); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/api/client/Client.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.api.client; 2 | 3 | import me.hp888.messenger.api.callback.Callback; 4 | import me.hp888.messenger.api.packet.Packet; 5 | import me.hp888.messenger.api.packet.PacketHandler; 6 | import me.hp888.messenger.connection.SocketConnection; 7 | import java.io.IOException; 8 | import java.net.InetSocketAddress; 9 | import java.util.Collection; 10 | import java.util.concurrent.ExecutorService; 11 | 12 | /** 13 | * @author hp888 on 07.11.2020. 14 | */ 15 | 16 | public interface Client { 17 | 18 | SocketConnection getConnection(); 19 | 20 | ExecutorService getPacketHandleExecutor(); 21 | 22 | /* connection */ 23 | 24 | void disconnect() throws IOException; 25 | 26 | void connect(InetSocketAddress address) throws IOException; 27 | 28 | /* packet subscription */ 29 | 30 | void unsubscribePackets(); 31 | 32 | void subscribePackets(String... classNames); 33 | 34 | boolean isPacketSubscribed(String className); 35 | 36 | /* packet handlers */ 37 | 38 | Collection getPacketHandlers(); 39 | 40 | void addPacketHandler(PacketHandler handler); 41 | 42 | void removePacketHandler(Class handlerClass); 43 | 44 | /* callbacks */ 45 | 46 | Callback getCallback(long id); 47 | 48 | /* sending packets */ 49 | 50 | void sendPacket(Packet packet) throws IOException; 51 | 52 | void sendPacket(Packet packet, Callback callback) throws IOException; 53 | 54 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/api/packet/CallbackPacket.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.api.packet; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import java.util.Objects; 6 | 7 | /** 8 | * @author hp888 on 08.11.2020. 9 | */ 10 | 11 | @Getter 12 | public abstract class CallbackPacket implements Packet { 13 | 14 | @Setter 15 | private long callbackId; 16 | private boolean response; 17 | private String errorMessage; 18 | 19 | public void setResponse() { 20 | this.response = true; 21 | } 22 | 23 | public boolean isSuccess() { 24 | return Objects.isNull(errorMessage); 25 | } 26 | 27 | public void setErrorMessage(String errorMessage) { 28 | this.errorMessage = errorMessage; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/api/packet/Packet.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.api.packet; 2 | 3 | import me.hp888.messenger.util.SerializeUtil; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.DataOutputStream; 6 | import java.io.IOException; 7 | import java.io.Serializable; 8 | import java.nio.charset.StandardCharsets; 9 | 10 | /** 11 | * @author hp888 on 07.11.2020. 12 | */ 13 | 14 | public interface Packet extends Serializable { 15 | 16 | default byte[] serialize() throws IOException { 17 | final byte[] packetData = SerializeUtil.serializeObject(this); 18 | final byte[] className = getClass().getName().getBytes(StandardCharsets.UTF_8); 19 | 20 | final int bufferSize = className.length + packetData.length + 8; // two ints are stored in 8 bytes 21 | 22 | try (final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(bufferSize); final DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream)) { 23 | dataOutputStream.writeInt(className.length); 24 | dataOutputStream.write(className); 25 | 26 | dataOutputStream.writeInt(packetData.length); 27 | dataOutputStream.write(packetData); 28 | 29 | return byteArrayOutputStream.toByteArray(); 30 | } 31 | } 32 | 33 | default void processPacket(PacketHandler handler) {} 34 | 35 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/api/packet/PacketHandler.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.api.packet; 2 | 3 | /** 4 | * @author hp888 on 07.11.2020. 5 | */ 6 | 7 | public interface PacketHandler { 8 | 9 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/api/packet/PacketHandlerManager.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.api.packet; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * @author hp888 on 07.11.2020. 7 | */ 8 | 9 | public final class PacketHandlerManager { 10 | 11 | private final Set subscribedPackets = new HashSet<>(); 12 | private final Set handlers = new HashSet<>(); 13 | 14 | public void subscribePackets(String... classNames) { 15 | subscribedPackets.addAll(Arrays.asList(classNames)); 16 | } 17 | 18 | public boolean isPacketSubscribed(String className) { 19 | return subscribedPackets.contains(className); 20 | } 21 | 22 | public void unsubscribePackets() { 23 | subscribedPackets.clear(); 24 | } 25 | 26 | public Collection getPacketHandlers() { 27 | return handlers; 28 | } 29 | 30 | public void removePacketHandler(Class handlerClass) { 31 | handlers.removeIf(handler -> handler.getClass().equals(handlerClass)); 32 | } 33 | 34 | public void addPacketHandler(PacketHandler handler) { 35 | handlers.add(handler); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/connection/SocketConnection.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.connection; 2 | 3 | import lombok.Getter; 4 | import me.hp888.messenger.api.packet.CallbackPacket; 5 | import me.hp888.messenger.api.packet.Packet; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.DataInputStream; 8 | import java.io.DataOutputStream; 9 | import java.io.IOException; 10 | import java.net.Socket; 11 | import java.util.Objects; 12 | 13 | /** 14 | * @author hp888 on 08.11.2020. 15 | */ 16 | 17 | @Getter 18 | public final class SocketConnection { 19 | 20 | private final Socket socket; 21 | 22 | private final DataInputStream inputStream; 23 | private final DataOutputStream outputStream; 24 | 25 | public SocketConnection(Socket socket) throws IOException { 26 | this.socket = socket; 27 | this.inputStream = new DataInputStream(socket.getInputStream()); 28 | this.outputStream = new DataOutputStream(socket.getOutputStream()); 29 | } 30 | 31 | public void sendPacket(Packet packet, Long callbackId) throws IOException { 32 | if (packet instanceof CallbackPacket && Objects.nonNull(callbackId)) { 33 | ((CallbackPacket) packet).setCallbackId(callbackId); 34 | } 35 | 36 | final byte[] serializedPacket = packet.serialize(); 37 | try (final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); final DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream)) { 38 | dataOutputStream.writeInt(serializedPacket.length); 39 | dataOutputStream.write(serializedPacket); 40 | dataOutputStream.flush(); 41 | 42 | outputStream.write(byteArrayOutputStream.toByteArray()); 43 | outputStream.flush(); 44 | } 45 | } 46 | 47 | public boolean isAlive() { 48 | return socket.isConnected() && !socket.isClosed(); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/packet/HeartbeatPacket.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.packet; 2 | 3 | import lombok.ToString; 4 | import me.hp888.messenger.api.packet.Packet; 5 | 6 | /** 7 | * @author hp888 on 08.11.2020. 8 | */ 9 | 10 | @ToString 11 | public final class HeartbeatPacket implements Packet { 12 | 13 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/thread/PacketReaderThread.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.thread; 2 | 3 | import me.hp888.messenger.api.callback.Callback; 4 | import me.hp888.messenger.api.client.Client; 5 | import me.hp888.messenger.api.packet.CallbackPacket; 6 | import me.hp888.messenger.api.packet.Packet; 7 | import me.hp888.messenger.connection.SocketConnection; 8 | import me.hp888.messenger.util.SerializeUtil; 9 | import java.io.ByteArrayInputStream; 10 | import java.io.DataInputStream; 11 | import java.io.IOException; 12 | import java.nio.charset.StandardCharsets; 13 | import java.util.Objects; 14 | 15 | /** 16 | * @author hp888 on 08.11.2020. 17 | */ 18 | 19 | public final class PacketReaderThread extends Thread { 20 | 21 | private final Client client; 22 | 23 | public PacketReaderThread(Client client) { 24 | super("Messenger PacketReaderThread"); 25 | this.client = client; 26 | } 27 | 28 | @Override 29 | public void run() { 30 | final SocketConnection connection = client.getConnection(); 31 | final DataInputStream inputStream = connection.getInputStream(); 32 | 33 | try { 34 | while (connection.isAlive()) { 35 | final int wholePacketSize = inputStream.readInt(); 36 | final byte[] wholePacketData = new byte[wholePacketSize]; 37 | inputStream.readFully(wholePacketData); 38 | 39 | final DataInputStream packetStream = new DataInputStream(new ByteArrayInputStream(wholePacketData)); 40 | final int classNameLength = packetStream.readInt(); 41 | final byte[] className = new byte[classNameLength]; 42 | packetStream.readFully(className); 43 | 44 | final int packetSize = packetStream.readInt(); 45 | if (!client.isPacketSubscribed(new String(className, StandardCharsets.UTF_8))) { 46 | packetStream.skipBytes(packetSize); 47 | continue; 48 | } 49 | 50 | final byte[] packetData = new byte[packetSize]; 51 | packetStream.readFully(packetData); 52 | 53 | if (packetData.length == 0) { 54 | continue; 55 | } 56 | 57 | client.getPacketHandleExecutor().execute(() -> { 58 | final Packet packet = SerializeUtil.deserializeObject(packetData); 59 | if (handleCallback(packet)) { 60 | return; 61 | } 62 | 63 | client.getPacketHandlers() 64 | .forEach(packet::processPacket); 65 | }); 66 | } 67 | } catch (IOException ex) { 68 | System.out.println("[INFO] Disconnected from messenger! Cause: " + ex.toString()); 69 | ex.printStackTrace(); 70 | } 71 | 72 | throw new ThreadDeath(); 73 | } 74 | 75 | @SuppressWarnings("unchecked") 76 | private boolean handleCallback(Packet packet) { 77 | if (packet instanceof CallbackPacket) { 78 | final CallbackPacket callbackPacket = (CallbackPacket) packet; 79 | if (callbackPacket.getCallbackId() != 0L && callbackPacket.isResponse()) { 80 | final Callback callback = client.getCallback(callbackPacket.getCallbackId()); 81 | if (Objects.nonNull(callback)) { 82 | if (callbackPacket.isSuccess()) { 83 | callback.done(callbackPacket); 84 | } else { 85 | callback.error(callbackPacket.getErrorMessage()); 86 | } 87 | } 88 | 89 | return true; 90 | } 91 | } 92 | 93 | return false; 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /messaging-client/src/main/java/me/hp888/messenger/util/SerializeUtil.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.util; 2 | 3 | import org.nustaq.serialization.FSTConfiguration; 4 | 5 | /** 6 | * @author hp888 on 07.11.2020. 7 | */ 8 | 9 | public final class SerializeUtil { 10 | 11 | private static final FSTConfiguration FAST_SERIALIZER = FSTConfiguration.createDefaultConfiguration(); 12 | 13 | private SerializeUtil() {} 14 | 15 | public static byte[] serializeObject(Object object) { 16 | return FAST_SERIALIZER.asByteArray(object); 17 | } 18 | 19 | @SuppressWarnings("unchecked") 20 | public static T deserializeObject(byte[] data) { 21 | return (T) FAST_SERIALIZER.asObject(data); 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /messaging-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | messaging-system 7 | me.hp888 8 | 1.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | messaging-server 13 | 14 | 15 | 1.8 16 | 1.8 17 | 18 | 19 | 20 | clean install 21 | 22 | 23 | org.apache.maven.plugins 24 | maven-jar-plugin 25 | 3.2.0 26 | 27 | 28 | 29 | true 30 | me.hp888.messenger.Bootstrap 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /messaging-server/src/main/java/me/hp888/messenger/Bootstrap.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger; 2 | 3 | /** 4 | * @author hp888 on 07.11.2020. 5 | */ 6 | 7 | public final class Bootstrap { 8 | 9 | public static void main(String[] args) { 10 | final Thread thread = new Thread(MessengerServer.getInstance()::start); 11 | thread.setName("Server thread"); 12 | thread.start(); 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /messaging-server/src/main/java/me/hp888/messenger/MessengerServer.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import me.hp888.messenger.client.Client; 6 | import me.hp888.messenger.client.ClientManager; 7 | import me.hp888.messenger.thread.PacketWriterThread; 8 | import me.hp888.messenger.thread.ServerShutdownThread; 9 | import java.io.IOException; 10 | import java.net.InetSocketAddress; 11 | import java.net.ServerSocket; 12 | import java.net.Socket; 13 | import java.util.logging.Level; 14 | import java.util.logging.Logger; 15 | 16 | /** 17 | * @author hp888 on 07.11.2020. 18 | */ 19 | 20 | @Getter 21 | @Setter 22 | public final class MessengerServer { 23 | 24 | @Getter 25 | private static final MessengerServer instance = new MessengerServer(); 26 | 27 | private final Logger logger = Logger.getLogger(MessengerServer.class.getSimpleName()); 28 | private final ClientManager clientManager = new ClientManager(this); 29 | 30 | private boolean running; 31 | 32 | void start() { 33 | running = true; 34 | 35 | startThreads(); 36 | startServer(); 37 | } 38 | 39 | private void startThreads() { 40 | new PacketWriterThread(this).start(); 41 | Runtime.getRuntime().addShutdownHook(new ServerShutdownThread(this)); 42 | } 43 | 44 | private void startServer() { 45 | final ServerSocket serverSocket; 46 | 47 | try { 48 | serverSocket = new ServerSocket(); 49 | serverSocket.bind(new InetSocketAddress(System.getProperty("host", "127.0.0.1"), Integer.parseInt(System.getProperty("port", "9999")))); 50 | serverSocket.setSoTimeout(10000); 51 | } catch (IOException ex) { 52 | logger.log(Level.SEVERE, "Cannot bind server on " + System.getProperty("host", "127.0.0.1") + ":" + System.getProperty("port", "9999") + ", probably used by other application?", ex); 53 | return; 54 | } 55 | 56 | logger.info("Server bound on " + serverSocket.getInetAddress().toString()); 57 | 58 | while (!serverSocket.isClosed()) { 59 | final Socket socket; 60 | 61 | try { 62 | socket = serverSocket.accept(); 63 | } catch (IOException ex) { 64 | if (ex.getMessage().equals("Accept timed out")) { 65 | continue; 66 | } 67 | 68 | logger.log(Level.SEVERE, "Cannot accept new connection!", ex); 69 | continue; 70 | } 71 | 72 | try { 73 | clientManager.addClient(new Client(socket)); 74 | } catch (IOException ex) { 75 | logger.log(Level.SEVERE, "Cannot get I/O stream from recently accepted connection!"); 76 | } 77 | 78 | } 79 | 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /messaging-server/src/main/java/me/hp888/messenger/client/Client.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.client; 2 | 3 | import lombok.Data; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.DataInputStream; 6 | import java.io.DataOutputStream; 7 | import java.io.IOException; 8 | import java.net.InetAddress; 9 | import java.net.Socket; 10 | import java.util.Queue; 11 | import java.util.concurrent.ConcurrentLinkedQueue; 12 | 13 | /** 14 | * @author hp888 on 07.11.2020. 15 | */ 16 | 17 | @Data 18 | public final class Client { 19 | 20 | private final Socket socket; 21 | private final InetAddress address; 22 | 23 | private final DataInputStream inputStream; 24 | private final DataOutputStream outputStream; 25 | 26 | public Client(Socket socket) throws IOException { 27 | this.socket = socket; 28 | this.address = socket.getInetAddress(); 29 | this.inputStream = new DataInputStream(socket.getInputStream()); 30 | this.outputStream = new DataOutputStream(socket.getOutputStream()); 31 | } 32 | 33 | private final Queue outgoingPackets = new ConcurrentLinkedQueue<>(); 34 | 35 | void sendPacket(byte[] bytes) throws IOException { 36 | final int bufferSize = bytes.length + 4; // single int value is stored in 4 bytes 37 | try (final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(bufferSize); final DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream)) { 38 | dataOutputStream.writeInt(bytes.length); 39 | dataOutputStream.write(bytes, 0, bytes.length); 40 | dataOutputStream.flush(); 41 | 42 | outputStream.write(byteArrayOutputStream.toByteArray()); 43 | outputStream.flush(); 44 | } 45 | } 46 | 47 | public boolean isConnected() { 48 | return socket.isConnected() && !socket.isClosed(); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /messaging-server/src/main/java/me/hp888/messenger/client/ClientManager.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.client; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import me.hp888.messenger.MessengerServer; 6 | import me.hp888.messenger.thread.PacketReaderThread; 7 | import java.io.IOException; 8 | import java.util.Collections; 9 | import java.util.Set; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | import java.util.logging.Level; 13 | 14 | /** 15 | * @author hp888 on 07.11.2020. 16 | */ 17 | 18 | @Getter 19 | @RequiredArgsConstructor 20 | public final class ClientManager { 21 | 22 | private final MessengerServer server; 23 | private final Set clients = Collections.newSetFromMap(new ConcurrentHashMap<>()); 24 | 25 | private final AtomicInteger threadCounter = new AtomicInteger(); 26 | 27 | public void addClient(Client client) { 28 | clients.add(client); 29 | threadCounter.incrementAndGet(); 30 | server.getLogger().info("Client has connected to the server! [" + client.getAddress().toString() + "]"); 31 | 32 | new PacketReaderThread(server, client) 33 | .start(); 34 | } 35 | 36 | public void removeClient(Client client) { 37 | clients.remove(client); 38 | threadCounter.decrementAndGet(); 39 | server.getLogger().info("Client has disconnected from the server! [" + client.getAddress().toString() + "]"); 40 | } 41 | 42 | public void sendPacket(byte[] packet) { 43 | clients.forEach(client -> { 44 | try { 45 | client.sendPacket(packet); 46 | } catch (IOException ex) { 47 | server.getLogger().log(Level.SEVERE, "Cannot send packet to client!", ex); 48 | removeClient(client); 49 | } 50 | }); 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /messaging-server/src/main/java/me/hp888/messenger/thread/PacketReaderThread.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.thread; 2 | 3 | import me.hp888.messenger.MessengerServer; 4 | import me.hp888.messenger.client.Client; 5 | import java.io.DataInputStream; 6 | import java.io.EOFException; 7 | import java.util.Objects; 8 | import java.util.logging.Level; 9 | 10 | /** 11 | * @author hp888 on 07.11.2020. 12 | */ 13 | 14 | public final class PacketReaderThread extends Thread { 15 | 16 | private final MessengerServer server; 17 | private final Client client; 18 | 19 | public PacketReaderThread(MessengerServer server, Client client) { 20 | super("Messenger Packet Reader Thread #" + server.getClientManager().getThreadCounter().get()); 21 | this.server = server; 22 | this.client = client; 23 | } 24 | 25 | @Override 26 | public void run() { 27 | final DataInputStream inputStream = client.getInputStream(); 28 | 29 | try { 30 | while (client.isConnected()) { 31 | final byte[] bytes = new byte[inputStream.readInt()]; 32 | inputStream.readFully(bytes); 33 | 34 | client.getOutgoingPackets().add(bytes); 35 | } 36 | } catch (Exception ex) { 37 | if (!(ex instanceof EOFException) && (Objects.isNull(ex.getMessage()) || !ex.getMessage().equals("Connection reset"))) { 38 | server.getLogger().log(Level.SEVERE, "Cannot read packet!", ex); 39 | } 40 | 41 | server.getClientManager().removeClient(client); 42 | } 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /messaging-server/src/main/java/me/hp888/messenger/thread/PacketWriterThread.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.thread; 2 | 3 | import me.hp888.messenger.MessengerServer; 4 | import me.hp888.messenger.util.ThreadUtil; 5 | 6 | /** 7 | * @author hp888 on 07.11.2020. 8 | */ 9 | 10 | public final class PacketWriterThread extends Thread { 11 | 12 | private final MessengerServer server; 13 | 14 | public PacketWriterThread(MessengerServer server) { 15 | super("Messenger Packet Writer Thread"); 16 | this.server = server; 17 | } 18 | 19 | @Override 20 | public void run() { 21 | while (server.isRunning()) { 22 | server.getClientManager().getClients().forEach(client -> { 23 | while (!client.getOutgoingPackets().isEmpty()) { 24 | server.getClientManager().sendPacket(client.getOutgoingPackets().poll()); 25 | } 26 | }); 27 | 28 | ThreadUtil.sleep(1L); 29 | } 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /messaging-server/src/main/java/me/hp888/messenger/thread/ServerShutdownThread.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.thread; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import me.hp888.messenger.MessengerServer; 5 | 6 | /** 7 | * @author hp888 on 09.11.2020. 8 | */ 9 | 10 | @RequiredArgsConstructor 11 | public final class ServerShutdownThread extends Thread { 12 | 13 | private final MessengerServer server; 14 | 15 | @Override 16 | public void run() { 17 | server.getLogger().info("Shutting down server..."); 18 | server.setRunning(false); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /messaging-server/src/main/java/me/hp888/messenger/util/ThreadUtil.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.util; 2 | 3 | import me.hp888.messenger.MessengerServer; 4 | import java.util.logging.Level; 5 | 6 | /** 7 | * @author hp888 on 07.11.2020. 8 | */ 9 | 10 | public final class ThreadUtil { 11 | 12 | private ThreadUtil() {} 13 | 14 | public static void sleep(long ms) { 15 | try { 16 | Thread.sleep(ms); 17 | } catch (InterruptedException ex) { 18 | MessengerServer.getInstance().getLogger().log(Level.SEVERE, "Cannot interrupt thread " + Thread.currentThread().getName() + "!", ex); 19 | Thread.currentThread().stop(); 20 | } 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /messenger-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | messaging-system 7 | me.hp888 8 | 1.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | messenger-plugin 13 | 14 | 15 | 1.8 16 | 1.8 17 | 18 | 19 | 20 | 21 | bungeecord-repo 22 | https://oss.sonatype.org/content/repositories/snapshots 23 | 24 | 25 | spigot-repo 26 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 27 | 28 | 29 | velocity 30 | https://repo.velocitypowered.com/snapshots/ 31 | 32 | 33 | 34 | 35 | 36 | org.spigotmc 37 | spigot-api 38 | 1.16.4-R0.1-SNAPSHOT 39 | provided 40 | 41 | 42 | net.md-5 43 | bungeecord-api 44 | 1.16-R0.4-SNAPSHOT 45 | jar 46 | provided 47 | 48 | 49 | com.velocitypowered 50 | velocity-api 51 | 1.0.0-SNAPSHOT 52 | provided 53 | 54 | 55 | me.hp888 56 | messaging-client 57 | 1.0-SNAPSHOT 58 | compile 59 | 60 | 61 | com.google.code.gson 62 | gson 63 | 2.8.5 64 | provided 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /messenger-plugin/src/main/java/me/hp888/messenger/bukkit/BukkitMessengerPlugin.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.bukkit; 2 | 3 | import me.hp888.messenger.MessengerClient; 4 | import me.hp888.messenger.api.client.Client; 5 | import me.hp888.messenger.shared.Messenger; 6 | import me.hp888.messenger.shared.MessengerPlugin; 7 | import me.hp888.messenger.shared.config.Configuration; 8 | import org.bukkit.plugin.java.JavaPlugin; 9 | import java.io.IOException; 10 | import java.io.File; 11 | import java.net.InetSocketAddress; 12 | import java.util.Objects; 13 | import java.util.logging.Level; 14 | 15 | /** 16 | * @author hp888 on 09.11.2020. 17 | */ 18 | 19 | public final class BukkitMessengerPlugin extends JavaPlugin { 20 | 21 | private final Configuration configuration = new Configuration(); 22 | 23 | @Override 24 | public void onEnable() { 25 | try { 26 | configuration.load(new File(getDataFolder(), "config.json")); 27 | } catch (IOException ex) { 28 | getLogger().log(Level.SEVERE, "Cannot load configuration!", ex); 29 | getServer().getPluginManager().disablePlugin(this); 30 | return; 31 | } 32 | 33 | final Configuration.Pool pool = configuration.getPool(); 34 | final Client client; 35 | 36 | if (pool.isAdjustSizeAutomatically()) { 37 | client = new MessengerClient(); 38 | } else { 39 | client = new MessengerClient(Math.max(2, pool.getSize())); 40 | } 41 | 42 | try { 43 | client.connect(new InetSocketAddress(configuration.getHost(), configuration.getPort())); 44 | } catch (IOException ex) { 45 | getLogger().log(Level.SEVERE, "Cannot connect to remote server!", ex); 46 | getServer().getPluginManager().disablePlugin(this); 47 | return; 48 | } 49 | 50 | Messenger.setInstance(new MessengerPlugin(client, getLogger())); 51 | } 52 | 53 | @Override 54 | public void onDisable() { 55 | final MessengerPlugin messenger = Messenger.getInstance(); 56 | if (Objects.isNull(messenger)) { 57 | return; 58 | } 59 | 60 | try { 61 | messenger.disconnect(); 62 | } catch (IOException ignored) {} 63 | } 64 | } -------------------------------------------------------------------------------- /messenger-plugin/src/main/java/me/hp888/messenger/bungee/BungeeMessengerPlugin.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.bungee; 2 | 3 | import me.hp888.messenger.MessengerClient; 4 | import me.hp888.messenger.api.client.Client; 5 | import me.hp888.messenger.shared.Messenger; 6 | import me.hp888.messenger.shared.MessengerPlugin; 7 | import me.hp888.messenger.shared.config.Configuration; 8 | import net.md_5.bungee.api.plugin.Plugin; 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.net.InetSocketAddress; 12 | import java.util.Objects; 13 | import java.util.logging.Level; 14 | 15 | /** 16 | * @author hp888 on 09.11.2020. 17 | */ 18 | 19 | public final class BungeeMessengerPlugin extends Plugin { 20 | 21 | private final Configuration configuration = new Configuration(); 22 | 23 | @Override 24 | public void onEnable() { 25 | try { 26 | configuration.load(new File(getDataFolder(), "config.json")); 27 | } catch (IOException ex) { 28 | getLogger().log(Level.SEVERE, "Cannot load configuration!", ex); 29 | getProxy().stop(); 30 | return; 31 | } 32 | 33 | 34 | final Configuration.Pool pool = configuration.getPool(); 35 | final Client client; 36 | 37 | if (pool.isAdjustSizeAutomatically()) { 38 | client = new MessengerClient(); 39 | } else { 40 | client = new MessengerClient(Math.max(2, pool.getSize())); 41 | } 42 | 43 | try { 44 | client.connect(new InetSocketAddress(configuration.getHost(), configuration.getPort())); 45 | } catch (IOException ex) { 46 | getLogger().log(Level.SEVERE, "Cannot connect to remote server!", ex); 47 | getProxy().stop(); 48 | return; 49 | } 50 | 51 | Messenger.setInstance(new MessengerPlugin(client, getLogger())); 52 | 53 | } 54 | 55 | @Override 56 | public void onDisable() { 57 | final MessengerPlugin messenger = Messenger.getInstance(); 58 | if (Objects.isNull(messenger)) { 59 | return; 60 | } 61 | 62 | try { 63 | messenger.disconnect(); 64 | } catch (IOException ignored) {} 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /messenger-plugin/src/main/java/me/hp888/messenger/shared/Messenger.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.shared; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * @author hp888 on 09.11.2020. 8 | */ 9 | 10 | public final class Messenger { 11 | 12 | @Getter 13 | @Setter 14 | private static MessengerPlugin instance; 15 | 16 | private Messenger() { 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /messenger-plugin/src/main/java/me/hp888/messenger/shared/MessengerPlugin.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.shared; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import me.hp888.messenger.api.callback.Callback; 5 | import me.hp888.messenger.api.client.Client; 6 | import me.hp888.messenger.api.packet.Packet; 7 | import me.hp888.messenger.api.packet.PacketHandler; 8 | import java.io.IOException; 9 | import java.util.logging.Level; 10 | import java.util.logging.Logger; 11 | 12 | /** 13 | * @author hp888 on 09.11.2020. 14 | */ 15 | 16 | @RequiredArgsConstructor 17 | public final class MessengerPlugin { 18 | 19 | private final Client client; 20 | private final Logger logger; 21 | 22 | /* packet sending */ 23 | 24 | public void sendPacket(Packet packet) { 25 | try { 26 | client.sendPacket(packet); 27 | } catch (IOException ex) { 28 | logger.log(Level.SEVERE, "Cannot send packet \"" + packet.getClass().getSimpleName() + "\"!", ex); 29 | } 30 | } 31 | 32 | public void sendPacket(Packet packet, Callback callback) { 33 | try { 34 | client.sendPacket(packet, callback); 35 | } catch (IOException ex) { 36 | logger.log(Level.SEVERE, "Cannot send packet \"" + packet.getClass().getSimpleName() + "\"!", ex); 37 | } 38 | } 39 | 40 | /* packet registering */ 41 | 42 | public void unsubscribePackets() { 43 | client.unsubscribePackets(); 44 | } 45 | 46 | public void subscribePackets(String... classNames) { 47 | client.subscribePackets(classNames); 48 | } 49 | 50 | /* packet handlers */ 51 | 52 | public void addPacketHandler(PacketHandler handler) { 53 | client.addPacketHandler(handler); 54 | } 55 | 56 | public void removePacketHandler(Class handlerClass) { 57 | client.removePacketHandler(handlerClass); 58 | } 59 | 60 | public void disconnect() throws IOException { 61 | client.disconnect(); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /messenger-plugin/src/main/java/me/hp888/messenger/shared/config/Configuration.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.shared.config; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.google.gson.JsonParser; 5 | import lombok.Data; 6 | import lombok.Getter; 7 | import me.hp888.messenger.shared.Messenger; 8 | import java.io.File; 9 | import java.io.FileReader; 10 | import java.io.IOException; 11 | import java.nio.file.Files; 12 | import java.nio.file.StandardCopyOption; 13 | import java.util.Objects; 14 | 15 | /** 16 | * @author hp888 on 09.11.2020. 17 | */ 18 | 19 | @Getter 20 | public final class Configuration { 21 | 22 | private String host; 23 | private Pool pool; 24 | private int port; 25 | 26 | public void load(File file) throws IOException { 27 | file.getParentFile().mkdirs(); 28 | 29 | if (!file.exists()) { 30 | Files.copy(Messenger.class.getResourceAsStream("/config.json"), file.toPath(), StandardCopyOption.REPLACE_EXISTING); 31 | } 32 | 33 | final JsonObject jsonObject = new JsonParser().parse(new FileReader(file)) 34 | .getAsJsonObject(); 35 | 36 | final JsonObject poolObject = jsonObject.getAsJsonObject("pool"); 37 | if (Objects.isNull(poolObject)) { // Added because of config update. 38 | Files.delete(file.toPath()); 39 | Files.copy(Messenger.class.getResourceAsStream("/config.json"), file.toPath(), StandardCopyOption.REPLACE_EXISTING); 40 | } 41 | 42 | host = jsonObject.get("host").getAsString(); 43 | port = jsonObject.get("port").getAsInt(); 44 | 45 | pool = new Pool(poolObject.get("adjust-size-automatically").getAsBoolean(), poolObject.get("pool-size").getAsInt()); 46 | } 47 | 48 | @Data 49 | public final class Pool { 50 | 51 | private final boolean adjustSizeAutomatically; 52 | private final int size; 53 | 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /messenger-plugin/src/main/java/me/hp888/messenger/velocity/VelocityMessengerPlugin.java: -------------------------------------------------------------------------------- 1 | package me.hp888.messenger.velocity; 2 | 3 | import com.google.inject.Inject; 4 | import com.velocitypowered.api.event.Subscribe; 5 | import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; 6 | import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; 7 | import com.velocitypowered.api.plugin.Plugin; 8 | import com.velocitypowered.api.plugin.annotation.DataDirectory; 9 | import com.velocitypowered.api.proxy.ProxyServer; 10 | import me.hp888.messenger.MessengerClient; 11 | import me.hp888.messenger.api.client.Client; 12 | import me.hp888.messenger.shared.Messenger; 13 | import me.hp888.messenger.shared.MessengerPlugin; 14 | import me.hp888.messenger.shared.config.Configuration; 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.net.InetSocketAddress; 18 | import java.nio.file.Path; 19 | import java.util.Objects; 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | 23 | /** 24 | * @author hp888 on 10.11.2020. 25 | */ 26 | 27 | @Plugin(id = "messenger", 28 | name = "MessengerPlugin", 29 | authors = "HP888", 30 | version = "1.0" 31 | ) 32 | public final class VelocityMessengerPlugin { 33 | 34 | private final Configuration configuration; 35 | private final ProxyServer server; 36 | private final Path dataFolder; 37 | private final Logger logger; 38 | 39 | @Inject 40 | public VelocityMessengerPlugin(ProxyServer server, Logger logger, @DataDirectory Path dataFolder) { 41 | this.server = server; 42 | this.logger = logger; 43 | this.dataFolder = dataFolder; 44 | this.configuration = new Configuration(); 45 | } 46 | 47 | @Subscribe 48 | public void onProxyInitialization(ProxyInitializeEvent event) { 49 | try { 50 | configuration.load(new File(dataFolder.toFile(), "config.json")); 51 | } catch (IOException ex) { 52 | logger.log(Level.SEVERE, "Cannot load configuration!", ex); 53 | return; 54 | } 55 | 56 | final Configuration.Pool pool = configuration.getPool(); 57 | final Client client; 58 | 59 | if (pool.isAdjustSizeAutomatically()) { 60 | client = new MessengerClient(); 61 | } else { 62 | client = new MessengerClient(Math.max(2, pool.getSize())); 63 | } 64 | 65 | try { 66 | client.connect(new InetSocketAddress(configuration.getHost(), configuration.getPort())); 67 | } catch (IOException ex) { 68 | logger.log(Level.SEVERE, "Cannot connect to remote server!", ex); 69 | return; 70 | } 71 | 72 | Messenger.setInstance(new MessengerPlugin(client, logger)); 73 | } 74 | 75 | @Subscribe 76 | public void onProxyShutdown(ProxyShutdownEvent event) { 77 | final MessengerPlugin messenger = Messenger.getInstance(); 78 | if (Objects.isNull(messenger)) { 79 | return; 80 | } 81 | 82 | try { 83 | messenger.disconnect(); 84 | } catch (IOException ignored) {} 85 | } 86 | 87 | } -------------------------------------------------------------------------------- /messenger-plugin/src/main/resources/bungee.yml: -------------------------------------------------------------------------------- 1 | main: 'me.hp888.messenger.bungee.BungeeMessengerPlugin' 2 | version: '1.0' 3 | author: 'HP888' 4 | name: 'MessengerPlugin' -------------------------------------------------------------------------------- /messenger-plugin/src/main/resources/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "127.0.0.1", 3 | "port": 9999, 4 | "pool": { 5 | "adjust-size-automatically": true, 6 | "pool-size": 8 7 | } 8 | } -------------------------------------------------------------------------------- /messenger-plugin/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | main: 'me.hp888.messenger.bukkit.BukkitMessengerPlugin' 2 | version: '1.0' 3 | author: 'HP888' 4 | name: 'MessengerPlugin' -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.hp888 8 | messaging-system 9 | pom 10 | 1.1-SNAPSHOT 11 | 12 | messaging-server 13 | messaging-client 14 | messenger-plugin 15 | 16 | 17 | 18 | 19 | safemc-repository 20 | SafeMC Repository 21 | https://safemc.pl/repository/releases 22 | 23 | 24 | 25 | 26 | 27 | org.projectlombok 28 | lombok 29 | 1.18.12 30 | provided 31 | 32 | 33 | 34 | 35 | clean install 36 | 37 | 38 | org.apache.maven.plugins 39 | maven-shade-plugin 40 | 3.2.1 41 | 42 | 43 | package 44 | 45 | shade 46 | 47 | 48 | 49 | 50 | false 51 | ${project.name}-${project.version} 52 | 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-compiler-plugin 57 | 3.8.0 58 | 59 | 1.8 60 | 1.8 61 | 62 | 63 | 64 | 65 | 66 | --------------------------------------------------------------------------------