package net.ME1312.SubServers.Client.Bukkit.Network; import net.ME1312.SubServers.Client.Bukkit.Library.Exception.IllegalPacketException; import net.ME1312.SubServers.Client.Bukkit.Library.Version.Version; import net.ME1312.SubServers.Client.Bukkit.Network.Packet.*; import net.ME1312.SubServers.Client.Bukkit.SubPlugin; import org.bukkit.Bukkit; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.net.Socket; import java.net.SocketException; import java.util.HashMap; public final class SubDataClient { private static HashMap, String> pOut = new HashMap, String>(); private static HashMap pIn = new HashMap(); private static boolean defaults = false; private PrintWriter writer; private Socket socket; private String name; private SubPlugin plugin; /** * SubServers Client Instance * * @param plugin SubPlugin * @param address Bind Address * @param port Port * @throws IOException */ public SubDataClient(SubPlugin plugin, String name, InetAddress address, int port) throws IOException { socket = new Socket(address, port); this.plugin = plugin; this.name = name; this.writer = new PrintWriter(socket.getOutputStream(), true); if (!defaults) loadDefaults(); loop(); Bukkit.getScheduler().runTaskLater(plugin, () -> sendPacket(new PacketAuthorization(plugin)), 10); } private void loadDefaults() { defaults = true; registerPacket(new PacketAuthorization(plugin), "Authorization"); registerPacket(new PacketCommandServer(), "SubCommandServer"); registerPacket(new PacketCreateServer(), "SubCreateServer"); registerPacket(new PacketDownloadHostInfo(), "SubDownloadHostInfo"); registerPacket(new PacketDownloadLang(plugin), "SubDownloadLang"); registerPacket(new PacketDownloadPlayerList(), "SubDownloadPlayerList"); registerPacket(new PacketDownloadServerInfo(), "SubDownloadServerInfo"); registerPacket(new PacketDownloadServerList(), "SubDownloadServerList"); registerPacket(new PacketInfoPassthrough(), "SubInfoPassthrough"); registerPacket(new PacketInRunEvent(), "SubRunEvent"); registerPacket(new PacketInShutdown(), "SubShutdown"); registerPacket(new PacketLinkServer(plugin), "SubLinkServer"); registerPacket(new PacketStartServer(), "SubStartServer"); registerPacket(new PacketStopServer(), "SubStopServer"); registerPacket(new PacketTeleportPlayer(), "SubTeleportPlayer"); registerPacket(PacketAuthorization.class, "Authorization"); registerPacket(PacketCommandServer.class, "SubCommandServer"); registerPacket(PacketCreateServer.class, "SubCreateServer"); registerPacket(PacketDownloadHostInfo.class, "SubDownloadHostInfo"); registerPacket(PacketDownloadLang.class, "SubDownloadLang"); registerPacket(PacketDownloadPlayerList.class, "SubDownloadPlayerList"); registerPacket(PacketDownloadServerInfo.class, "SubDownloadServerInfo"); registerPacket(PacketDownloadServerList.class, "SubDownloadServerList"); registerPacket(PacketInfoPassthrough.class, "SubInfoPassthrough"); registerPacket(PacketLinkServer.class, "SubLinkServer"); registerPacket(PacketStartServer.class, "SubStartServer"); registerPacket(PacketStopServer.class, "SubStopServer"); registerPacket(PacketTeleportPlayer.class, "SubTeleportPlayer"); } private void loop() { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { try { BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); String input; while ((input = in.readLine()) != null) { try { JSONObject json = new JSONObject(input); PacketIn packet = decodePacket(json); try { packet.execute((json.keySet().contains("c")) ? json.getJSONObject("c") : null); } catch (Exception e) { new InvocationTargetException(e, "Exception while executing PacketIn").printStackTrace(); } } catch (IllegalPacketException e) { e.printStackTrace(); } catch (JSONException e) { new IllegalPacketException("Unknown Packet Format: " + input).printStackTrace(); } } try { destroy(true); } catch (IOException e1) { e1.printStackTrace(); } } catch (Exception e) { if (!(e instanceof SocketException)) e.printStackTrace(); try { destroy(true); } catch (IOException e1) { e1.printStackTrace(); } } }); } /** * Gets the Assigned Server Name * * @return Server Name */ public String getName() { return name; } /** * Gets the Server Socket * * @return Server Socket */ public Socket getClient() { return socket; } /** * Register Packet to the Network * * @param packet PacketIn to register * @param handle Handle to Bind */ public static void registerPacket(PacketIn packet, String handle) { pIn.put(handle, packet); } /** * Register Packet to the Network * * @param packet PacketOut to register * @param handle Handle to bind */ public static void registerPacket(Class packet, String handle) { pOut.put(packet, handle); } /** * Grab PacketIn Instance via handle * * @param handle Handle * @return PacketIn */ public static PacketIn getPacket(String handle) { return pIn.get(handle); } /** * Send Packet to Client * * @param packet Packet to send */ public void sendPacket(PacketOut packet) { try { writer.println(encodePacket(packet)); } catch (IllegalPacketException e) { e.printStackTrace(); } } /** * JSON Encode PacketOut * * @param packet PacketOut * @return JSON Formatted Packet * @throws IllegalPacketException */ protected static JSONObject encodePacket(PacketOut packet) throws IllegalPacketException { JSONObject json = new JSONObject(); if (!pOut.keySet().contains(packet.getClass())) throw new IllegalPacketException("Unknown PacketOut Channel: " + packet.getClass().getCanonicalName()); if (packet.getVersion().toString() == null) throw new NullPointerException("PacketOut Version cannot be null: " + packet.getClass().getCanonicalName()); JSONObject contents = packet.generate(); json.put("h", pOut.get(packet.getClass())); json.put("v", packet.getVersion().toString()); if (contents != null) json.put("c", contents); return json; } /** * JSON Decode PacketIn * * @param json JSON to Decode * @return PacketIn * @throws IllegalPacketException * @throws InvocationTargetException */ protected static PacketIn decodePacket(JSONObject json) throws IllegalPacketException, InvocationTargetException { if (!json.keySet().contains("h") || !json.keySet().contains("v")) throw new IllegalPacketException("Unknown Packet Format: " + json.toString()); if (!pIn.keySet().contains(json.getString("h"))) throw new IllegalPacketException("Unknown PacketIn Channel: " + json.getString("h")); PacketIn packet = pIn.get(json.getString("h")); if (!new Version(json.getString("v")).equals(packet.getVersion())) throw new IllegalPacketException("Packet Version Mismatch in " + json.getString("h") + ": " + json.getString("v") + "->" + packet.getVersion().toString()); return packet; } /** * Drops All Connections and Stops the SubData Listener * * @throws IOException */ public void destroy(boolean reconnect) throws IOException { if (socket != null) { final Socket socket = this.socket; this.socket = null; if (!socket.isClosed()) socket.close(); Bukkit.getLogger().info("SubServers > The SubData Connection was closed"); if (reconnect) { Bukkit.getLogger().info("SubServers > Attempting to reconnect in 10 seconds"); Bukkit.getScheduler().runTaskLater(plugin, () -> { try { plugin.subdata = new SubDataClient(plugin, name, socket.getInetAddress(), socket.getPort()); } catch (IOException e) { e.printStackTrace(); } }, 10 * 20); } plugin.subdata = null; } } }