From 1a8a911a12fed289298cfafa2544bcc3abc1c9ab Mon Sep 17 00:00:00 2001 From: Marc Baloup Date: Wed, 4 Feb 2015 17:42:58 -0500 Subject: [PATCH] Ajout du NetworkAPI --- NetworkAPI protocole.md | 79 ++++++++ make_jar.jardesc | 2 +- resources/plugin.yml | 4 +- .../plugin/pandacraftutils/ConfigManager.java | 17 ++ .../pandacraftutils/PandacraftUtils.java | 3 +- .../commands/CommandAdmin.java | 30 ++- .../network_api/NetworkAPI.java | 33 +++ .../network_api/NetworkAPIListener.java | 191 ++++++++++++++++++ .../network_api/RequestAnalyser.java | 87 ++++++++ .../pandacraftutils/network_api/Response.java | 19 ++ .../client_test/AbstractRequest.java | 31 +++ .../network_api/client_test/ClientTest.java | 37 ++++ .../client_test/RequestCommand.java | 12 ++ .../client_test/ResponseAnalyser.java | 63 ++++++ .../AbstractRequestExecutor.java | 48 +++++ .../RequestExecutorBroadcast.java | 23 +++ .../RequestExecutorCommand.java | 49 +++++ .../RequestExecutorCommandAsync.java | 36 ++++ 18 files changed, 753 insertions(+), 11 deletions(-) create mode 100644 NetworkAPI protocole.md create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/NetworkAPI.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/NetworkAPIListener.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/RequestAnalyser.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/Response.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/AbstractRequest.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/ClientTest.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/RequestCommand.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/ResponseAnalyser.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/AbstractRequestExecutor.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorBroadcast.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorCommand.java create mode 100644 src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorCommandAsync.java diff --git a/NetworkAPI protocole.md b/NetworkAPI protocole.md new file mode 100644 index 0000000..8b886d9 --- /dev/null +++ b/NetworkAPI protocole.md @@ -0,0 +1,79 @@ +Protocole de NetworkAPI +==================== +Ce fichier défini simplement le fonctionnement du protocole qui sera implémenté dans le package `net.mc_pandacraft.java.plugin.pandacraftutils.network_api` + +Il servira à faire communiquer le serveur Minecraft avec l'interface d'administration ou le site internet + +## Type de connexion +Connexion TCP + + +## Cryptage +Les communications devant rester dans un réseau privé (loopback, VNP) entre les systèmes composant le serveur, il n'est pas vraiment nécessaire de crypter les connexions. En d'autres termes, les clients effectuant les requêtes ne correspondent pas aux utilisateurs finaux, se trouvant sur les réseaux d'accès. + +## Sécurité +Même si le cryptage ne semble pas nécessaire, il faut tout de même sécuriser avec un système de "mot de passe", qui sera décrit en dessous + +## Structure d'une requête +La requête est construite en mode texte, sur plusieurs lignes. Chaque ligne se fini par un '\n' : + + - Mot de passe alphanumérique + '\n' + - Commande principale + '\n' + - Longueur des données, en octets + '\n' + - Valeur/données (pas de '\n' à la fin) + + Pour que l'analyse de la requête côté serveur puisse s'effectuer côté serveur, le flux qui va du client vers le serveur doit être fermée après envoi des données. + +### Exemple de paquet + ervg1e3r2c + command + 12 + say Salut :) + + +### Les commandes principaux + +#### `command` +Exécute la commande passée dans la partie **donnée** de la requête, comme si elle avait été exécutée par la console (`ConsoleCommandSender` dans Bukkit). Le résultat de l'exécution de la commande (valeur de retour de CommandExecutor.onCommand()) ne peux pas être retourné en réponse. Cependant, la non exécution de la commande sera indiqué dans la console du serveur + +#### `command_async` +Pareil que `command` mais cette fois, celle-ci n'est pas forcément exécutée dans le thread principal. Attention : certaines commandes ne peuvent pas fonctionner en asynchrone. Cette méthode est utile dans le cas où le thread principal ne répond plus + +#### `broadcast` +Affiche un message sur le chat pour tout le monde connecté. +Le message passé dans la partie **donnée** est diffusé tel quel dans le chat et sur la console (attention à la bonne utilisation des codes couleurs) + +#### `player_list` +Renvoi la liste des joueurs connectés. La valeur passé dans la partie **donnée** doit contenir, selon les besoins : + +- `disp_name` pour donner les noms d'affichage du genre [Admin]Pseudo +- `location` pour donner la localisation du joueur +- `ip` pour donner l'IP du joueur +- ... + +## Structure d'une réponse +La réponse est construite en mode texte, sur plusieurs lignes. Chaque ligne se fini par un '\n' : + +- Status de réponse (`OK` ou `ERROR`) + '\n' +- Longueur des données +- Données, si nécessaire,ou message d'erreur, si status != `ok` + +### Exemple de paquets +Réponse à une requête sans résultat qui a bien été exécuté + + OK + 0 + ---- +Réponse à une commande inexistante + + ERROR + 24 + command_not_exists + ---- +Réponse à une requête de type `player_list` + + OK + 56 + player\0disp_name + marcbal\0§f[§4Admin§f]§4marcbal§r + diff --git a/make_jar.jardesc b/make_jar.jardesc index 0acb522..8bd8e9f 100644 --- a/make_jar.jardesc +++ b/make_jar.jardesc @@ -1,6 +1,6 @@ - + diff --git a/resources/plugin.yml b/resources/plugin.yml index 207b661..86e0cf8 100644 --- a/resources/plugin.yml +++ b/resources/plugin.yml @@ -1,6 +1,6 @@ name: PandacraftUtils main: net.mc_pandacraft.java.plugin.pandacraftutils.PandacraftUtils -version: 3.4 +version: 3.5 @@ -67,7 +67,7 @@ commands: aliases: [am] admin: description: Administration - usage: /admin + usage: /admin [reload [config|network]] permission: pandacraft.admin diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/ConfigManager.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/ConfigManager.java index 37dcc6d..679c64d 100644 --- a/src/net/mc_pandacraft/java/plugin/pandacraftutils/ConfigManager.java +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/ConfigManager.java @@ -101,9 +101,14 @@ public class ConfigManager { + // TODO ajouter les valeurs par défaut dans config.yml EntitySpam_worlds = "creative"; // séparé avec des point-virgules EntitySpam_limitPerChunks = 50; + + // TODO ajouter les valeurs par défaut dans config.yml + NetworkAPI_passwd = "rgrgaethejtrvvzh47"; + initChatAnalysisBadWord(); @@ -147,6 +152,18 @@ public class ConfigManager { + /* + * NetworkAPI + */ + public String NetworkAPI_passwd; + + + + + + + + /* * Automessages diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/PandacraftUtils.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/PandacraftUtils.java index 73fcced..045e393 100644 --- a/src/net/mc_pandacraft/java/plugin/pandacraftutils/PandacraftUtils.java +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/PandacraftUtils.java @@ -16,6 +16,7 @@ import net.mc_pandacraft.java.plugin.pandacraftutils.modules.WESelectionDisplayM import net.mc_pandacraft.java.plugin.pandacraftutils.modules.cheat_protect.CreativCheatManager; import net.mc_pandacraft.java.plugin.pandacraftutils.modules.cheat_protect.EntitySpamManager; import net.mc_pandacraft.java.plugin.pandacraftutils.modules.cheat_protect.NoPvpProtectManager; +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.NetworkAPI; import net.mc_pandacraft.java.plugin.pandacraftutils.players.OnlinePlayerManager; import org.bukkit.entity.Player; @@ -87,9 +88,9 @@ public class PandacraftUtils extends JavaPlugin { tpsAnalysisManager = new TPSAnalysisManager(); autoMessagesManager = new AutoMessagesManager(); entitySpamManager = new EntitySpamManager(); - + NetworkAPI.loadNewInstance(); getServer().getScheduler().runTaskLater(this, new Runnable() { @Override public void run() { new PlayerDataCleaner(instance); } diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/commands/CommandAdmin.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/commands/CommandAdmin.java index 414a7ca..577e8a9 100644 --- a/src/net/mc_pandacraft/java/plugin/pandacraftutils/commands/CommandAdmin.java +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/commands/CommandAdmin.java @@ -1,6 +1,8 @@ package net.mc_pandacraft.java.plugin.pandacraftutils.commands; import net.mc_pandacraft.java.plugin.pandacraftutils.ConfigManager; +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.NetworkAPI; +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.NetworkAPIListener; import org.bukkit.ChatColor; import org.bukkit.command.Command; @@ -15,17 +17,31 @@ public class CommandAdmin extends AbstractCommandExecutor { @Override public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { - if (args.length == 0) return false; - if (args[0].equalsIgnoreCase("reload")) { - ConfigManager.reloadConfig(); - sender.sendMessage(ChatColor.GREEN+"La configuration de PandacraftUtils viens d'être rechargée"); + if (args.length == 0){ + sender.sendMessage(ChatColor.GREEN+plugin.getDescription().getFullName()); + NetworkAPIListener nwAPI = NetworkAPIListener.getInstance(); + if (nwAPI.isAlive()) + sender.sendMessage(ChatColor.GREEN+"NetworkAPI écoute au port "+NetworkAPIListener.getInstance().getPort()); + else + sender.sendMessage(ChatColor.GREEN+"NetworkAPI n'est pas démarré. Voir la console pour les détails, ou faites /admin reload "); return true; } - if (args[0].equalsIgnoreCase("version")) { - sender.sendMessage(ChatColor.GREEN+plugin.getDescription().getFullName()); - return true; + + if (args[0].equalsIgnoreCase("reload") && args.length >= 2) { + if (args[1].equalsIgnoreCase("config")) { + ConfigManager.reloadConfig(); + sender.sendMessage(ChatColor.GREEN+"La configuration de PandacraftUtils viens d'être rechargée"); + return true; + } + + if (args[1].equalsIgnoreCase("network")) { + sender.sendMessage(ChatColor.GREEN+"Redémarrage de NetworkAPI"); + NetworkAPI.loadNewInstance(); + sender.sendMessage(ChatColor.GREEN+"Redémarrage terminée"); + return true; + } } diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/NetworkAPI.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/NetworkAPI.java new file mode 100644 index 0000000..e43fede --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/NetworkAPI.java @@ -0,0 +1,33 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api; + +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.request_executors.RequestExecutorBroadcast; +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.request_executors.RequestExecutorCommand; +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.request_executors.RequestExecutorCommandAsync; + +public class NetworkAPI { + + public static void loadNewInstance() { + + + NetworkAPIListener.loadNewInstance(); + + /* + * Initialisation des exécuteurs des commandes réseau + * LEs constructeurs s'occupent eux même de se référencer dans l'instance de la classe NetworkAPIListener + */ + new RequestExecutorCommand(); + new RequestExecutorBroadcast(); + new RequestExecutorCommandAsync(); + + } + /* + public static void main(String[] args) throws Throwable { + loadNewInstance(); + + System.out.println(NetworkAPIListener.getInstance().getCommandList()); + + NetworkAPIListener.getInstance().join(); + } + */ + +} diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/NetworkAPIListener.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/NetworkAPIListener.java new file mode 100644 index 0000000..4f32f1e --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/NetworkAPIListener.java @@ -0,0 +1,191 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api; + +import java.io.IOException; +import java.io.PrintStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Arrays; +import java.util.HashMap; + +import org.bukkit.ChatColor; + +import net.mc_pandacraft.java.plugin.pandacraftutils.PandacraftUtils; +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.RequestAnalyser.BadRequestException; +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.request_executors.AbstractRequestExecutor; + +public class NetworkAPIListener extends Thread { + + + private static NetworkAPIListener instance; + + /** + * Retourne l'unique instance de la classe. Si elle n'existe pas, on tente de la créer.
+ * Cette classe étant un enfant de Thread, la création de l'instance provoque son exécution + * @return L'unique instance de la classe + */ + + public synchronized static NetworkAPIListener getInstance() { + if (instance == null) + loadNewInstance(); + return instance; + } + + public synchronized static void loadNewInstance() { + if (instance != null && instance.isAlive()) { + instance.closeServerSocket(); // cet appel est censé provoquer l'arrêt du thread + try { instance.join(); } catch (InterruptedException e) { } + } + instance = new NetworkAPIListener(); + instance.start(); + } + + + + + + + + private PandacraftUtils plugin = PandacraftUtils.getInstance(); + private int port = plugin.getServer().getPort()+9; + private ServerSocket serverSocket; + private HashMap requestExecutors = new HashMap(); + + private NetworkAPIListener() { + super("NetworkAPI Listener"); + System.setProperty("file.encoding", "UTF-8"); + plugin.getServer().getLogger().info("System property 'file.encoding' was set to 'UTF-8'"); + + + } + + @Override + public void run() { + synchronized (this) { + try { + serverSocket = new ServerSocket(port); + } catch (IOException e) { + plugin.getServer().getLogger().severe(e.getMessage()); + System.err.println(e.getMessage()); + return; + } + } + + plugin.getServer().getLogger().info(ChatColor.GREEN+"NetworkAPIListener à l'écoute sur le port "+port); + + int i=0; + + try { + // réception des connexion client + while (!serverSocket.isClosed()) { + Socket socketClient = serverSocket.accept(); + new PacketExecutor(socketClient, i++).start(); + } + } catch(IOException e) { } + + synchronized (this) { + try { + if (!serverSocket.isClosed()) + serverSocket.close(); + } catch (IOException e) { } + } + + plugin.getServer().getLogger().info(ChatColor.GREEN+"NetworkAPIListener ferme le port "+port); + } + + /** + * Ferme le ServerSocket. Ceci provoque l'arrêt du thread associé à l'instance de la classe + */ + private synchronized void closeServerSocket() { + if (serverSocket != null) + { + try { + serverSocket.close(); + } catch (IOException e) { } + } + } + + + public int getPort() { return port; } + + + + + public void registerRequestExecutor(String command, AbstractRequestExecutor executor) { + requestExecutors.put(command, executor); + } + + public AbstractRequestExecutor getRequestExecutor(String command) { + return requestExecutors.get(command); + } + + + public String getCommandList() { + return Arrays.toString(requestExecutors.keySet().toArray()); + } + +} + + + + + + + + + + + + + + +/** + * Prends en charge un socket client et le transmet au gestionnaire de paquet correspondant.
+ * La connexion est fermée après chaque requête du client (règle pouvant évoluer) + * @author Marc + * + */ +class PacketExecutor extends Thread { + private PandacraftUtils plugin = PandacraftUtils.getInstance(); + private Socket socket; + + public PacketExecutor(Socket s, int iteration) { + super("NetworkAPI Input Packet #"+iteration); + socket = s; + } + + @Override + public void run() { + try { + + // analyse de la requête + RequestAnalyser analyse = new RequestAnalyser(socket); + + + AbstractRequestExecutor executor = NetworkAPIListener.getInstance().getRequestExecutor(analyse.command); + + executor.execute(analyse.data, socket); + + + + } catch (IOException e) { + + plugin.getServer().getLogger().severe("IOException "+e.getMessage()); + } catch (BadRequestException e) { + Response rep = new Response(); + rep.good = false; + rep.data = e.getMessage(); + try { + rep.sendPacket(new PrintStream(socket.getOutputStream())); + } catch (IOException e1) { } + + plugin.getServer().getLogger().severe("BadRequestException "+e.getMessage()); + + } catch(Throwable e) { + e.printStackTrace(); + } + + try { + socket.close(); + } catch (Exception e) { } + } +} \ No newline at end of file diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/RequestAnalyser.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/RequestAnalyser.java new file mode 100644 index 0000000..de7852f --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/RequestAnalyser.java @@ -0,0 +1,87 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; + +import net.mc_pandacraft.java.plugin.pandacraftutils.ConfigManager; + +public class RequestAnalyser { + + private NetworkAPIListener networkAPIListener = NetworkAPIListener.getInstance(); + + private final String pass = ConfigManager.getInstance().NetworkAPI_passwd; + + public final String command; + public final String data; + + public RequestAnalyser(Socket socket) throws IOException, BadRequestException { + if (socket == null || socket.isClosed() || socket.isInputShutdown()) throw new IllegalArgumentException("le socket doit être non null et doit être ouvert sur le flux d'entrée"); + + // on lis la réponse + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + String line; + + + + // lecture de la première ligne + line = in.readLine(); + if (line == null || !line.equals(pass)) + throw new BadRequestException("wrong_password"); + + + + + + // lecture de la deuxième ligne + line = in.readLine(); + if (line == null || networkAPIListener.getRequestExecutor(line) == null) + throw new BadRequestException("command_not_exists"); + command = line; + + + + // lecture de la troisième ligne + line = in.readLine(); + + int data_size = 0; + try { + data_size = Integer.parseInt(line); + } catch (NumberFormatException e) { throw new BadRequestException("wrong_data_size_format"); } + + + // lecture du reste + StringBuilder sB_data = new StringBuilder(); + char[] c = new char[100]; + int nbC = 0; + while((nbC = in.read(c)) != -1) + sB_data.append(c, 0, nbC); + + data = sB_data.toString(); + + if (data.length() != data_size) + throw new BadRequestException("wrong_data_size"); + + + socket.shutdownInput(); + } + + + + + + + public class BadRequestException extends Exception { + + private static final long serialVersionUID = 1L; + + public BadRequestException(String message) { + super(message); + } + + } + + +} diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/Response.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/Response.java new file mode 100644 index 0000000..b125cc5 --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/Response.java @@ -0,0 +1,19 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api; + +import java.io.PrintStream; + +public class Response { + public boolean good = true; + public String data = ""; + + + public void sendPacket(PrintStream out) { + + if (data == null) data = ""; + + out.print((good?"OK":"ERROR")+"\n"); + out.print(data.length()+"\n"); + out.print(data); + out.flush(); + } +} diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/AbstractRequest.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/AbstractRequest.java new file mode 100644 index 0000000..b65cbe9 --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/AbstractRequest.java @@ -0,0 +1,31 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api.client_test; + +import java.io.PrintStream; + +public abstract class AbstractRequest { + + private final String pass = "test"; + private String command; + private String data; + + + protected AbstractRequest(String cmd) { + if (cmd == null || cmd.isEmpty()) throw new IllegalArgumentException("Un message doit-être défini"); + command = cmd; + } + + + protected void setData(String d) { + if (d == null) d = ""; + data = d; + } + + + public void sendPacket(PrintStream out) { + out.print(pass+"\n"); + out.print(command+"\n"); + out.print(data.length()+"\n"); + out.print(data); + out.flush(); + } +} diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/ClientTest.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/ClientTest.java new file mode 100644 index 0000000..92fb3a1 --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/ClientTest.java @@ -0,0 +1,37 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api.client_test; + +import java.io.PrintStream; +import java.net.Socket; + +public class ClientTest { + + public static void main(String[] args) throws Exception { + System.out.println("--- connexion ..."); + Socket s = new Socket("localhost", 12485); + System.out.println("--- connecté"); + + PrintStream out = new PrintStream(s.getOutputStream()); + + AbstractRequest request = new RequestCommand("say Salut :)"); + + request.sendPacket(out); + + s.shutdownOutput(); + + System.out.println("--- requête envoyée"); + request.sendPacket(System.out); + System.out.println(); + + System.out.println("--- réponse du serveur :"); + ResponseAnalyser response = new ResponseAnalyser(s); + + System.out.println(response.good); + System.out.println(response.data); + + s.close(); + } + + +} + + diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/RequestCommand.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/RequestCommand.java new file mode 100644 index 0000000..2b0e318 --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/RequestCommand.java @@ -0,0 +1,12 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api.client_test; + +public class RequestCommand extends AbstractRequest { + + + public RequestCommand(String command) { + super("command"); + setData(command); + } + + +} diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/ResponseAnalyser.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/ResponseAnalyser.java new file mode 100644 index 0000000..fd2c5b6 --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/client_test/ResponseAnalyser.java @@ -0,0 +1,63 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api.client_test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; + +public class ResponseAnalyser { + /** + * Indique si la requête s'est bien exécutée (l'entête de la réponse est 'ok') + */ + public final boolean good; + + + public final String data; + + + public ResponseAnalyser(Socket socket) throws IOException { + if (socket == null || socket.isClosed() || socket.isInputShutdown()) throw new IllegalArgumentException("le socket doit être non null et doit être ouvert sur le flux d'entrée"); + + // on lis la réponse + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + String line; + + + // lecture de la première ligne + line = in.readLine(); + good = line.equalsIgnoreCase("OK"); + + + + + // lecture de la deuxième ligne + line = in.readLine(); + + int data_size = 0; + try { + data_size = Integer.parseInt(line); + } catch (NumberFormatException e) { throw new RuntimeException("Réponse mal formée : la deuxième ligne doit-être un nombre entier"); } + + + + + + + // lecture du reste + StringBuilder sB_data = new StringBuilder(); + char[] c = new char[100]; + int nbC = 0; + while((nbC = in.read(c)) != -1) + sB_data.append(c, 0, nbC); + data = sB_data.toString(); + + if (data.length() != data_size) + throw new RuntimeException("Réponse mal formée : "+data_size+" caractères annoncée dans la requête, mais "+data.length()+" s'y trouvent."); + + + } + + + +} diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/AbstractRequestExecutor.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/AbstractRequestExecutor.java new file mode 100644 index 0000000..634e03e --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/AbstractRequestExecutor.java @@ -0,0 +1,48 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api.request_executors; + +import java.io.IOException; +import java.io.PrintStream; +import java.net.Socket; + +import net.mc_pandacraft.java.plugin.pandacraftutils.PandacraftUtils; +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.NetworkAPIListener; +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.Response; + +public abstract class AbstractRequestExecutor { + + protected PandacraftUtils plugin = PandacraftUtils.getInstance(); + + + + public final String command; + + + public AbstractRequestExecutor(String cmd) { + command = cmd.toLowerCase(); + NetworkAPIListener.getInstance().registerRequestExecutor(command, this); + } + + + + public void execute(String data, Socket socket) throws IOException { + if (socket == null || socket.isClosed() || socket.isOutputShutdown()) throw new IllegalArgumentException("le socket doit être non null et doit être ouvert sur le flux d'entrée"); + + + Response rep = run(data); + + + + rep.sendPacket(new PrintStream(socket.getOutputStream())); + + } + + + /** + * + * @param data La représentation sous forme de String des données envoyés dans la requête + * @return La réponse à retourner au client + */ + protected abstract Response run(String data); + + +} diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorBroadcast.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorBroadcast.java new file mode 100644 index 0000000..f8eec11 --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorBroadcast.java @@ -0,0 +1,23 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api.request_executors; + +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.Response; + +public class RequestExecutorBroadcast extends AbstractRequestExecutor { + + public RequestExecutorBroadcast() { + super("broadcast"); + } + + + @Override + protected Response run(String data) { + + plugin.broadcast(data, false); + + Response rep = new Response(); + rep.good = true; + rep.data = ""; + return rep; + } + +} diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorCommand.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorCommand.java new file mode 100644 index 0000000..49cc790 --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorCommand.java @@ -0,0 +1,49 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api.request_executors; + +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.Response; + +public class RequestExecutorCommand extends AbstractRequestExecutor { + + public RequestExecutorCommand() { + super("command"); + // TODO Auto-generated constructor stub + } + + @Override + protected Response run(String data) { + + plugin.getServer().getScheduler().runTask(plugin, new Runnable() { + String command; + public void run() { + try + { + boolean succes = plugin.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), command); + + if (!succes) + plugin.getLogger().warning("Can't execute command"); + } + catch (Exception e) + { + plugin.getLogger().severe(e.getMessage()); + } + + + } + + public Runnable init(String cmd) { + command = cmd; + return this; + } + + + }.init(data)); + + Response rep = new Response(); + rep.good = true; + rep.data = ""; + + + return rep; + } + +} diff --git a/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorCommandAsync.java b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorCommandAsync.java new file mode 100644 index 0000000..9f30273 --- /dev/null +++ b/src/net/mc_pandacraft/java/plugin/pandacraftutils/network_api/request_executors/RequestExecutorCommandAsync.java @@ -0,0 +1,36 @@ +package net.mc_pandacraft.java.plugin.pandacraftutils.network_api.request_executors; + +import net.mc_pandacraft.java.plugin.pandacraftutils.network_api.Response; + +public class RequestExecutorCommandAsync extends AbstractRequestExecutor { + + public RequestExecutorCommandAsync() { + super("command_async"); + } + + @Override + protected Response run(String data) { + Response rep = new Response(); + + try + { + rep.good = plugin.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), data); + + if (!rep.good) + { + plugin.getLogger().warning("Can't execute command"); + rep.data = "command sent but CommandExecutor has not return success"; + } + } + catch (Exception e) + { + plugin.getLogger().severe(e.getMessage()); + rep.good = false; + rep.data = "Exception : "+e.getMessage(); + } + + + return rep; + } + +}