Mise à jour du bot à une version de JDA plus récente, et ajout de commentaires
This commit is contained in:
parent
c456837148
commit
6721dd4f6d
47
build.gradle
47
build.gradle
@ -13,11 +13,13 @@ apply plugin: 'java'
|
|||||||
|
|
||||||
compileJava.options.encoding = 'UTF-8'
|
compileJava.options.encoding = 'UTF-8'
|
||||||
|
|
||||||
// In this section you declare where to find the dependencies of your project
|
|
||||||
repositories {
|
repositories {
|
||||||
// Use jcenter for resolving your dependencies.
|
mavenCentral()
|
||||||
// You can declare any Maven/Ivy/file repository here.
|
|
||||||
jcenter()
|
maven {
|
||||||
|
name 'm2-dv8tion'
|
||||||
|
url 'https://m2.dv8tion.net/releases'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
@ -31,7 +33,7 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task apiJar(type: Jar) {
|
task apiJar(type: Jar) {
|
||||||
archiveName = "JuliabotAPI.jar"
|
archiveFileName = "JuliabotAPI.jar"
|
||||||
group 'build'
|
group 'build'
|
||||||
description "Fait un jar avec juste l'api"
|
description "Fait un jar avec juste l'api"
|
||||||
from(sourceSets.main.output) {
|
from(sourceSets.main.output) {
|
||||||
@ -40,7 +42,7 @@ task apiJar(type: Jar) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task internalddonJar(type: Jar) {
|
task internalddonJar(type: Jar) {
|
||||||
archiveName = "JuliabotInternaddon_beta.jar"
|
archiveFileName = "JuliabotInternaddon_beta.jar"
|
||||||
group 'build'
|
group 'build'
|
||||||
description "Fait un jar avec juste l'addon interne"
|
description "Fait un jar avec juste l'addon interne"
|
||||||
from(sourceSets.main.output) {
|
from(sourceSets.main.output) {
|
||||||
@ -51,36 +53,29 @@ task internalddonJar(type: Jar) {
|
|||||||
task execute(type:JavaExec) {
|
task execute(type:JavaExec) {
|
||||||
group 'execution'
|
group 'execution'
|
||||||
description "Compile et execute le fichier jar"
|
description "Compile et execute le fichier jar"
|
||||||
main = 'com.bernard.juliabot.Julia'
|
mainClass = 'com.bernard.juliabot.Julia'
|
||||||
classpath = sourceSets.main.runtimeClasspath
|
classpath = sourceSets.main.runtimeClasspath
|
||||||
}
|
}
|
||||||
|
|
||||||
task copyDependencies(type: Copy) {
|
task copyDependencies(type: Copy) {
|
||||||
group 'build'
|
group 'build'
|
||||||
from configurations.compile
|
from configurations.default
|
||||||
into 'dependencies'
|
into 'dependencies'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// This dependency is exported to consumers, that is to say found on their compile classpath.
|
|
||||||
api 'org.apache.commons:commons-math3:3.6.1'
|
implementation 'org.slf4j:slf4j-nop:1.7.25'
|
||||||
|
|
||||||
|
implementation 'net.dv8tion:JDA:4.4.0_352'
|
||||||
|
|
||||||
|
implementation 'com.thedeanda:lorem:2.1'
|
||||||
|
|
||||||
|
implementation 'commons-io:commons-io:2.6'
|
||||||
|
|
||||||
|
implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.22'
|
||||||
|
|
||||||
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
|
implementation 'com.github.mpkorstanje:simmetrics-core:4.1.1'
|
||||||
implementation 'com.google.guava:guava:23.0'
|
|
||||||
|
|
||||||
// Use JUnit test framework
|
|
||||||
testImplementation 'junit:junit:4.12'
|
|
||||||
|
|
||||||
compile 'org.slf4j:slf4j-nop:1.7.25'
|
|
||||||
|
|
||||||
compile 'net.dv8tion:JDA:4.2.0_189'
|
|
||||||
|
|
||||||
compile 'com.thedeanda:lorem:2.1'
|
|
||||||
|
|
||||||
compile 'commons-io:commons-io:2.6'
|
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/mysql/mysql-connector-java
|
|
||||||
compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.21'
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
89
src/main/java/com/bernard/juliabot/AppelACommande.java
Normal file
89
src/main/java/com/bernard/juliabot/AppelACommande.java
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package com.bernard.juliabot;
|
||||||
|
|
||||||
|
import static com.bernard.juliabot.api.Julia.erreur;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import com.bernard.juliabot.api.CCommande;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objet utilitaire représentant l'appel à une commande, qui suivera l'execution de la
|
||||||
|
* commande et permet de les gérer dans des threads séparés.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AppelACommande {
|
||||||
|
|
||||||
|
Method called;
|
||||||
|
CCommande argument;
|
||||||
|
String name;
|
||||||
|
String cname;
|
||||||
|
Object caller;
|
||||||
|
Thread commandThread;
|
||||||
|
Throwable exitValue = null;
|
||||||
|
volatile boolean running;
|
||||||
|
volatile boolean started;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée l'objet en spécifiant simplement ses paramètres.
|
||||||
|
* @param called La méthode qu'il faut appeler pour executer la commande.
|
||||||
|
* @param argument L'argument à cette méthode, «comment» la commande doit être lancée.
|
||||||
|
* @param name Le nom de la commande tel qu'il a été demandé.
|
||||||
|
* @param cname Le nom de la commande l'identifiant, sans alias.
|
||||||
|
* @param caller L'objet sur lequel doit être invoquée la commande.
|
||||||
|
*/
|
||||||
|
public AppelACommande(Method called, CCommande argument, String name, String cname, Object caller) {
|
||||||
|
this.called = called;
|
||||||
|
this.argument = argument;
|
||||||
|
this.name = name;
|
||||||
|
this.cname = cname;
|
||||||
|
this.caller = caller;
|
||||||
|
this.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Définit le therad d'appel de la fonction.
|
||||||
|
*/
|
||||||
|
public void setThread(Thread commandThread) {
|
||||||
|
this.commandThread = commandThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Définit la valeur de retour du programme (un Throwable en java)
|
||||||
|
* @param t
|
||||||
|
*/
|
||||||
|
public void setExitValue(Throwable t) {
|
||||||
|
this.exitValue = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* impose la terminaison de l'execution de la commande.
|
||||||
|
*/
|
||||||
|
public void termine() {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Teste si la commande est en cours de résolution
|
||||||
|
*/
|
||||||
|
public boolean isRunning() {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met le thread courant en pause jusqu'à ce que la commande soit résolue.
|
||||||
|
*/
|
||||||
|
public void waitFin() {
|
||||||
|
while(running) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(42);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
erreur("On s'est fait intérrompre !",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,59 +0,0 @@
|
|||||||
package com.bernard.juliabot;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
import com.bernard.juliabot.api.CCommande;
|
|
||||||
|
|
||||||
public class CommandCalled {
|
|
||||||
|
|
||||||
Method called;
|
|
||||||
CCommande argument;
|
|
||||||
String name;
|
|
||||||
String cname;
|
|
||||||
Object caller;
|
|
||||||
Thread commandThread;
|
|
||||||
Throwable exitValue = null;
|
|
||||||
volatile boolean running;
|
|
||||||
volatile boolean started;
|
|
||||||
|
|
||||||
public CommandCalled(Method called, CCommande argument, String name, String cname, Object caller) {
|
|
||||||
this.called = called;
|
|
||||||
this.argument = argument;
|
|
||||||
this.name = name;
|
|
||||||
this.cname = cname;
|
|
||||||
this.caller = caller;
|
|
||||||
this.running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setThread(Thread commandThread) {
|
|
||||||
this.commandThread = commandThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExitValue(Throwable t) {
|
|
||||||
this.exitValue = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ended() {
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRunning() {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void waitForExecution() {
|
|
||||||
while(running) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(42);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
System.err.println("Icapacité de pauser le thread : ");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -6,25 +6,25 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.bernard.juliabot.api.CCommande;
|
import com.bernard.juliabot.api.CCommande;
|
||||||
import com.bernard.juliabot.api.Command;
|
import com.bernard.juliabot.api.Commande;
|
||||||
|
|
||||||
|
//TODO la javadoc
|
||||||
public class CommandeSurchargee {
|
public class CommandeSurchargee {
|
||||||
|
|
||||||
String name;
|
String nom;
|
||||||
Command command;
|
Commande commande;
|
||||||
|
|
||||||
Map<Set<Class<?>>,Method> versions = new HashMap<>();
|
Map<Set<Class<?>>,Method> versions = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public CommandeSurchargee(Command c) {
|
public CommandeSurchargee(Commande c) {
|
||||||
this.name = c.name();
|
this.nom = c.name();
|
||||||
this.command = c;
|
this.commande = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Method getExecutor(CCommande commande) {
|
public Method getExecuteur(CCommande commande) {
|
||||||
Set<Class<?>> critargs = checkFiliature(Stream.of(commande.getClass()).collect(Collectors.toSet()));
|
Set<Class<?>> critargs = checkFiliature(Stream.of(commande.getClass()).collect(Collectors.toSet()));
|
||||||
System.out.println("////////"+critargs);
|
|
||||||
return versions.get(versions.keySet().stream().filter(cr -> critargs.containsAll(cr)).findAny().orElse(null));
|
return versions.get(versions.keySet().stream().filter(cr -> critargs.containsAll(cr)).findAny().orElse(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,11 +77,15 @@ public class CommandeSurchargee {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CommandeSurchargee [name=" + name + ", versions=" + versions + "]";
|
return "CommandeSurchargee [name=" + nom + ", versions=" + versions + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDesc() {
|
public String getDesc() {
|
||||||
return command.description();
|
return commande.description();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Commande getCommande() {
|
||||||
|
return commande;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,7 @@
|
|||||||
package com.bernard.juliabot;
|
package com.bernard.juliabot;
|
||||||
|
|
||||||
|
import static com.bernard.juliabot.api.Julia.erreur;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -16,38 +18,88 @@ import java.util.regex.Matcher;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.bernard.juliabot.Julia.Laboratory;
|
import com.bernard.juliabot.Julia.Laboratoire;
|
||||||
import com.bernard.juliabot.api.Command;
|
import com.bernard.juliabot.api.Commande;
|
||||||
import com.bernard.juliabot.api.Discord;
|
import com.bernard.juliabot.api.EventDiscord;
|
||||||
import com.bernard.juliabot.api.JuLIAddon;
|
import com.bernard.juliabot.api.Juliaddon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Un objet de cette classe représente un juliaddon, hors contexte de chargement.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class JuliaAddon {
|
public class JuliaAddon {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Un pattern qui permettre d'extraire le paquet dans lequel est un fichier .class
|
||||||
|
*/
|
||||||
private static final Pattern pkgFromClassName = Pattern.compile("^(\\w+(\\.\\w+){2,})\\.\\w+(\\$\\w+)*$");
|
private static final Pattern pkgFromClassName = Pattern.compile("^(\\w+(\\.\\w+){2,})\\.\\w+(\\$\\w+)*$");
|
||||||
|
/*
|
||||||
|
* Un pattern permettant d'extraire la version d'un juliaddon d'un fichier.
|
||||||
|
*/
|
||||||
private static final Pattern jarNameParser = Pattern.compile("^([^_]+)_([^_]+)(_(.+))?.jar$");
|
private static final Pattern jarNameParser = Pattern.compile("^([^_]+)_([^_]+)(_(.+))?.jar$");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le pkg de l'addon.
|
||||||
|
*/
|
||||||
String pkg;
|
String pkg;
|
||||||
|
/**
|
||||||
|
* La version de l'addon.
|
||||||
|
*/
|
||||||
String version;
|
String version;
|
||||||
|
|
||||||
JarFile jarFile;
|
/**
|
||||||
long lastModified;
|
* Le fichier jar duquel a été chargé cet addon
|
||||||
Set<JarEntry> loaderEntries;
|
*/
|
||||||
|
JarFile fichierJar;
|
||||||
|
/**
|
||||||
|
* Le timestamp de dernière modification du fichier jar au chargement de l'addon, afin de pouvoir tester
|
||||||
|
* plus rapidement si il est à jour avec le fichier jar associé.
|
||||||
|
*/
|
||||||
|
long derniereModif;
|
||||||
|
/**
|
||||||
|
* Liste des entrées du fichier jar à contenant l'addon, trèèèèès utile dans le cas d'un jar avec plusieurs addons.
|
||||||
|
*/
|
||||||
|
Set<JarEntry> entreesDuLoader;
|
||||||
|
|
||||||
Map<Character,JuliaClassLoader> classLoaders;
|
/**
|
||||||
JuliaClassLoader unassignedClassLoader = null;
|
* Liste les classloaders associés à chaque laboratoire dans lequel est chargé cet addon.
|
||||||
|
*/
|
||||||
|
Map<Laboratoire,JuliaClassLoader> classLoaders;
|
||||||
|
/**
|
||||||
|
* Un classloader non assigné, qui est créé afin de récupérer des informations sur l'addon à sa création, et qui
|
||||||
|
* peut être réutilisé pour un laboratoire.
|
||||||
|
*/
|
||||||
|
JuliaClassLoader classLoaderNonAssigne = null;
|
||||||
|
|
||||||
JuLIAddon addon;
|
/**
|
||||||
|
* L'annotation à l'origine de l'addon.
|
||||||
|
*/
|
||||||
|
Juliaddon addon;
|
||||||
|
/**
|
||||||
|
* La classe de cet annotation.
|
||||||
|
*/
|
||||||
Class<?> addonClass;
|
Class<?> addonClass;
|
||||||
|
|
||||||
public JuliaAddon(JarFile jar) throws JarWithMultipleAddonsException {
|
/**
|
||||||
|
* Crée un addon à partir de toutes les entrées d'un fichier jar.
|
||||||
|
* @param jar Le fichier jar à lire.
|
||||||
|
* @throws JarAuxMultiplesAddonsException Si plusieurs addons sont présents dans le fichier jar.
|
||||||
|
*/
|
||||||
|
public JuliaAddon(JarFile jar) throws JarAuxMultiplesAddonsException {
|
||||||
this(jar,jar.stream().collect(Collectors.toSet()));
|
this(jar,jar.stream().collect(Collectors.toSet()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JuliaAddon(JarFile jar,Set<JarEntry> entriesToRead) throws JarWithMultipleAddonsException {
|
/**
|
||||||
jarFile = jar;
|
* Crée un addon à partir des entrées jar spécifiées.
|
||||||
loaderEntries = entriesToRead;
|
* @param jar Le fichier à lire.
|
||||||
lastModified = new File(jar.getName()).lastModified();
|
* @param entreesALire Les entrées à lire.
|
||||||
|
* @throws JarAuxMultiplesAddonsException Si plusieurs addons sont dans ces entrées.
|
||||||
|
*/
|
||||||
|
public JuliaAddon(JarFile jar,Set<JarEntry> entreesALire) throws JarAuxMultiplesAddonsException {
|
||||||
|
fichierJar = jar;
|
||||||
|
entreesDuLoader = entreesALire;
|
||||||
|
derniereModif = new File(jar.getName()).lastModified();
|
||||||
classLoaders = new HashMap<>();
|
classLoaders = new HashMap<>();
|
||||||
|
|
||||||
//Parsing du nom du fichier
|
//Parsing du nom du fichier
|
||||||
@ -61,59 +113,117 @@ public class JuliaAddon {
|
|||||||
|
|
||||||
|
|
||||||
//Sets addon,pkg,version(si redefini) et addonClass
|
//Sets addon,pkg,version(si redefini) et addonClass
|
||||||
unassignedClassLoader = new JuliaClassLoader(jar, entriesToRead,new DummyLaboratory());
|
classLoaderNonAssigne = new JuliaClassLoader(jar, entreesALire,new LaboFactice());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized JuliaClassLoader newClassLoader(Laboratory laboratory) {
|
/**
|
||||||
if(unassignedClassLoader==null)
|
* Crée un classloader pour le laboratoire donné.
|
||||||
|
* @param laboratoire le laboratoire qui sera associé au classloader.
|
||||||
|
* @return Un classloader qui peut charger ce Juliaddon.
|
||||||
|
*/
|
||||||
|
public synchronized JuliaClassLoader nouveauClassLoader(Laboratoire laboratoire) {
|
||||||
|
if(classLoaderNonAssigne==null)
|
||||||
try {
|
try {
|
||||||
JuliaClassLoader cl = new JuliaClassLoader(jarFile, loaderEntries,laboratory);
|
JuliaClassLoader cl = new JuliaClassLoader(fichierJar, entreesDuLoader,laboratoire);
|
||||||
classLoaders.put(laboratory.laboratory, cl);
|
classLoaders.put(laboratoire, cl);
|
||||||
return cl;
|
return cl;
|
||||||
} catch (JarWithMultipleAddonsException e) {
|
} catch (JarAuxMultiplesAddonsException e) {
|
||||||
System.err.println("Cette erreur n'est pas censée arriver, alerte rouge");
|
erreur("Cette erreur n'est pas censée arriver, alerte rouge");
|
||||||
System.exit(685533990);
|
System.exit(685533990);
|
||||||
}
|
}
|
||||||
|
|
||||||
JuliaClassLoader cl = unassignedClassLoader;
|
JuliaClassLoader cl = classLoaderNonAssigne;
|
||||||
unassignedClassLoader = null;
|
classLoaderNonAssigne = null;
|
||||||
cl.laboratory = laboratory;
|
cl.laboratoire = laboratoire;
|
||||||
classLoaders.put(laboratory.laboratory, cl);
|
classLoaders.put(laboratoire, cl);
|
||||||
return cl;
|
return cl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
public String getName() {
|
* Récupère le nom de cet addon, tel que spécifié par le développeur.
|
||||||
return addon.name();
|
*/
|
||||||
|
public String getNom() {
|
||||||
|
return addon.nom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie la version de cet addon.
|
||||||
|
*/
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie le pkg de cet addon (qu'on peut voir comme son ID)
|
||||||
|
*/
|
||||||
|
public String getPkg() {
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JarFile getFichierJar() {
|
||||||
|
return fichierJar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDerniereModif() {
|
||||||
|
return derniereModif;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JuliaClassLoader getLoader(Laboratoire labo) {
|
||||||
|
return classLoaders.get(labo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Un classloader prévu pour lire des Juliaddons depuis des entrées de fichier jar.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class JuliaClassLoader extends ClassLoader {
|
public class JuliaClassLoader extends ClassLoader {
|
||||||
|
|
||||||
Map<String,Class<?>> loadedClasses;
|
/**
|
||||||
Set<JarEntry> entries;
|
* Enregistres les classes déjà chargées pour un chargement plus rapide.
|
||||||
|
*/
|
||||||
|
Map<String,Class<?>> classesChargees;
|
||||||
|
/**
|
||||||
|
* L'ensemble des entrées que ce classloader à «le droit» de lire.
|
||||||
|
*/
|
||||||
|
Set<JarEntry> entrees;
|
||||||
|
/**
|
||||||
|
* Le fichier jar associé à ce classloader.
|
||||||
|
*/
|
||||||
JarFile jar;
|
JarFile jar;
|
||||||
Laboratory laboratory = null;
|
/**
|
||||||
|
* Le laboratoire associé à ce classloader.
|
||||||
|
*/
|
||||||
|
Laboratoire laboratoire = null;
|
||||||
|
|
||||||
HashSet<Method> registeredCommands;
|
/**
|
||||||
HashSet<Method> registeredEvents;
|
* Liste les commandes enregistrées par ce classloader.
|
||||||
|
*/
|
||||||
|
Set<Method> commandesEnregistrees;
|
||||||
|
/**
|
||||||
|
* Liste les events enregistrées par ce classloader.
|
||||||
|
*/
|
||||||
|
Set<Method> eventsEnregistrees;
|
||||||
|
|
||||||
public JuliaClassLoader(JarFile jar,Set<JarEntry> entriesToRead,Laboratory labo) throws JarWithMultipleAddonsException {
|
/**
|
||||||
|
* Crée un classloader pour un certain jeu d'entrées jar dans un laboratoire.
|
||||||
|
* @param jar le fichier jar duquel lire les entrées.
|
||||||
|
* @param entreesALire Les entrées à lire pour ce classloader
|
||||||
|
* @param labo Le laboratoire dans lequel est plongé ce classloader.
|
||||||
|
* @throws JarAuxMultiplesAddonsException Si plusieurs addons sont trouvés dans le jar. Un classloader, un addon.
|
||||||
|
*/
|
||||||
|
public JuliaClassLoader(JarFile jar,Set<JarEntry> entreesALire,Laboratoire labo) throws JarAuxMultiplesAddonsException {
|
||||||
super();
|
super();
|
||||||
entries = entriesToRead;
|
entrees = entreesALire;
|
||||||
this.jar = jar;
|
this.jar = jar;
|
||||||
loadedClasses = new HashMap<>();
|
classesChargees = new HashMap<>();
|
||||||
this.laboratory = labo;
|
this.laboratoire = labo;
|
||||||
Set<Class<?>> readClasses = new HashSet<>();
|
Set<Class<?>> readClasses = new HashSet<>();
|
||||||
Map<String,JarEntry> juliaddons = new HashMap<>();
|
Map<String,JarEntry> juliaddons = new HashMap<>();
|
||||||
for(JarEntry entry : entriesToRead) {
|
for(JarEntry entry : entreesALire) {
|
||||||
if(entry.isDirectory())
|
if(entry.isDirectory())
|
||||||
continue;
|
continue;
|
||||||
if(!entry.getName().endsWith(".class"))
|
if(!entry.getName().endsWith(".class"))
|
||||||
@ -130,37 +240,37 @@ public class JuliaAddon {
|
|||||||
readClasses.add(clazz);
|
readClasses.add(clazz);
|
||||||
//Instantiated class
|
//Instantiated class
|
||||||
|
|
||||||
if(clazz.isAnnotationPresent(JuLIAddon.class)) {
|
if(clazz.isAnnotationPresent(Juliaddon.class)) {
|
||||||
//Declare package and new addon
|
//Declare package and new addon
|
||||||
Matcher m = pkgFromClassName.matcher(clazz.getName());
|
Matcher m = pkgFromClassName.matcher(clazz.getName());
|
||||||
if(!m.matches())
|
if(!m.matches())
|
||||||
throw new IllegalArgumentException("Le nom de la classe est invalide pour un Juliaddon (il faut au moins trois de profondeur dans le package) : "+clazz.getName());
|
throw new IllegalArgumentException("Le nom de la classe est invalide pour un Juliaddon (il faut au moins trois de profondeur dans le package) : "+clazz.getName());
|
||||||
String pkg = m.group(1);
|
String pkg = m.group(1);
|
||||||
|
if(pkg==null)
|
||||||
|
throw new IllegalArgumentException("Imposible de récupérer le pkg.");
|
||||||
if(juliaddons.containsKey(pkg))
|
if(juliaddons.containsKey(pkg))
|
||||||
throw new IllegalArgumentException("Il existe deja un juliaddon dans le package "+pkg+" , d<><64>placez "+clazz.getName()+" ou "+juliaddons.get(pkg).getName());
|
throw new IllegalArgumentException("Il existe deja un juliaddon dans le package "+pkg+" , déplacez "+clazz.getName()+" ou "+juliaddons.get(pkg).getName());
|
||||||
juliaddons.put(pkg, entry);
|
juliaddons.put(pkg, entry);
|
||||||
//If overwritten, will JarWithMultipleAddonsException
|
//If overwritten, will JarWithMultipleAddonsException
|
||||||
JuliaAddon.this.addon = clazz.getAnnotation(JuLIAddon.class);
|
JuliaAddon.this.addon = clazz.getAnnotation(Juliaddon.class);
|
||||||
JuliaAddon.this.pkg = pkg;
|
JuliaAddon.this.pkg = pkg;
|
||||||
JuliaAddon.this.version = addon.version().isEmpty()?version:addon.version();
|
JuliaAddon.this.version = addon.version().isEmpty()?version:addon.version();
|
||||||
JuliaAddon.this.addonClass = clazz;
|
JuliaAddon.this.addonClass = clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
}catch (ClassFormatError e) {
|
}catch (ClassFormatError e) {
|
||||||
System.err.println("Impossible de lire cette classe, son format est incorrect ... veuillez recompiler le jar");
|
erreur("Impossible de lire cette classe, son format est incorrect ... veuillez recompiler le jar",e);
|
||||||
e.printStackTrace();
|
|
||||||
continue;
|
continue;
|
||||||
}catch(SecurityException e) {
|
}catch(SecurityException e) {
|
||||||
System.err.println("Vous essayez de mettre cette classe dans un package interdit ! Honte a vous");
|
erreur("Vous essayez de mettre cette classe dans un package interdit ! Honte a vous",e);
|
||||||
e.printStackTrace();
|
|
||||||
continue;
|
continue;
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
System.err.println("Le fichier "+entry.getName()+" ne d<><64>cris pas un Juliaddon valide, il n'a donc pas <20><>t<EFBFBD><74> charg<72><67>, mais faites attention !");
|
erreur("Le fichier "+entry.getName()+" ne décris pas un Juliaddon valide, il n'a donc pas été chargé, mais faites attention !",e);
|
||||||
e.printStackTrace();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(juliaddons.size()<1)
|
||||||
|
throw new IllegalStateException("Aucun addon présent dans le fichier !");
|
||||||
//Toutes les classes du Jar ont été lues : Si plusieurs addons, on rentre
|
//Toutes les classes du Jar ont été lues : Si plusieurs addons, on rentre
|
||||||
//dans le if pour lever l'exception, sinon, on initialise le JuliaClassLoader
|
//dans le if pour lever l'exception, sinon, on initialise le JuliaClassLoader
|
||||||
if(juliaddons.size() > 1) {
|
if(juliaddons.size() > 1) {
|
||||||
@ -170,7 +280,7 @@ public class JuliaAddon {
|
|||||||
for (String pkg : juliaddons.keySet())
|
for (String pkg : juliaddons.keySet())
|
||||||
addonsEntriesVector.put(pkg, new HashSet<>());
|
addonsEntriesVector.put(pkg, new HashSet<>());
|
||||||
|
|
||||||
eLoop : for(JarEntry entry : entriesToRead) {
|
eLoop : for(JarEntry entry : entreesALire) {
|
||||||
if(entry.isDirectory())
|
if(entry.isDirectory())
|
||||||
continue;
|
continue;
|
||||||
if(!entry.getName().endsWith(".class"))
|
if(!entry.getName().endsWith(".class"))
|
||||||
@ -187,26 +297,28 @@ public class JuliaAddon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Si le code atteint ici, le JarEntry n'appartient a aucun pkg valide
|
//Si le code atteint ici, le JarEntry n'appartient a aucun pkg valide
|
||||||
System.err.println("Ce jar contiens plusieurs juliaddons. Nichtsdestotroz le fichier "+entry.getName()+" n'a pas de Juliaddon dans son package ou au dessus ... je ne charge donc pas la classe (attention, ca peux ammener a des ClassNotFoundException !!!)");
|
erreur("Ce jar contiens plusieurs juliaddons. "
|
||||||
|
+ "Nichtsdestotroz le fichier "+entry.getName()+" n'a pas de Juliaddon dans son package ou au dessus."
|
||||||
|
+ "je ne charge donc pas la classe (attention, ça peux ammener a des ClassNotFoundException !)");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
addonsEntries = new HashSet<>(addonsEntriesVector.values());
|
addonsEntries = new HashSet<>(addonsEntriesVector.values());
|
||||||
throw new JarWithMultipleAddonsException(addonsEntries);
|
throw new JarAuxMultiplesAddonsException(addonsEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Initialisation du JuliaClassloader
|
// Initialisation du JuliaClassloader
|
||||||
//Les parametres addon, pkg,version et addonCLass ont d<EFBFBD><EFBFBD>j<EFBFBD><EFBFBD> <EFBFBD><EFBFBD>t<EFBFBD><EFBFBD> initialis<EFBFBD><EFBFBD>s lors de l'it<EFBFBD><EFBFBD>ration des fichiers du jar
|
// Les paramètres addon, pkg,version et addonCLass ont déjà été initialisés lors de l'itération des fichiers du jar
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||||
if(loadedClasses.containsKey(name))
|
if(classesChargees.containsKey(name))
|
||||||
return loadedClasses.get(name);
|
return classesChargees.get(name);
|
||||||
///Recherche d'une entry qui collerai
|
///Recherche d'une entry qui collerai
|
||||||
String fileName = name.replaceAll("\\.", "/")+".class";
|
String fileName = name.replaceAll("\\.", "/")+".class";
|
||||||
Optional<JarEntry> oentry = entries.stream().filter(je -> je.getName().equals(fileName)).findAny();
|
Optional<JarEntry> oentry = entrees.stream().filter(je -> je.getName().equals(fileName)).findAny();
|
||||||
if(oentry.isPresent()) {
|
if(oentry.isPresent()) {
|
||||||
try {
|
try {
|
||||||
JarEntry entry = oentry.get();
|
JarEntry entry = oentry.get();
|
||||||
@ -215,19 +327,18 @@ public class JuliaAddon {
|
|||||||
reader.read(classData);
|
reader.read(classData);
|
||||||
reader.close();
|
reader.close();
|
||||||
Class<?> clazz = defineClass(name,classData,0,(int) entry.getSize());
|
Class<?> clazz = defineClass(name,classData,0,(int) entry.getSize());
|
||||||
loadedClasses.put(name, clazz);
|
classesChargees.put(name, clazz);
|
||||||
return clazz;
|
return clazz;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.err.println("Impossible de lire les donn<6E><6E>es du fichier "+oentry.get().getName()+" dans le jar "+jar.getName()+" je peux vous dire adieu je pense");
|
erreur("Impossible de lire les données du fichier "+oentry.get().getName()+" dans le jar "+jar.getName()+" je peux vous dire adieu je pense",e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JuliaClassLoader cl = laboratory.findClassLoader(name);
|
JuliaClassLoader cl = laboratoire.trouveLeClassLoader(name);
|
||||||
if(cl != null)
|
if(cl != null)
|
||||||
try {
|
try {
|
||||||
return cl.loadClass(name, resolve);
|
return cl.loadClass(name, resolve);
|
||||||
}catch(ClassNotFoundException e) {
|
}catch(ClassNotFoundException e) {
|
||||||
throw new ClassNotFoundException("J'ai délégué le chargement de la classe mais j'aurais pas du ... cette classe ne doit pas exister dans l'addon "+cl.getAddon().getName(),e);
|
throw new ClassNotFoundException("J'ai délégué le chargement de la classe mais j'aurais pas du ... cette classe ne doit pas exister dans l'addon "+cl.getAddon().getNom(),e);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
try {
|
try {
|
||||||
@ -238,73 +349,113 @@ public class JuliaAddon {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerCommandsAndEvents() {
|
/**
|
||||||
registeredCommands = new HashSet<>();
|
* Enregistre dans le laboratoire toutes les commandes et
|
||||||
registeredEvents = new HashSet<>();
|
* les events présents dans les classes de ce classloader
|
||||||
|
*/
|
||||||
|
public void enregistrerCommadesEtEvents() {
|
||||||
|
commandesEnregistrees = new HashSet<>();
|
||||||
|
eventsEnregistrees = new HashSet<>();
|
||||||
Set<Method> toWatch = new HashSet<>();
|
Set<Method> toWatch = new HashSet<>();
|
||||||
Collections.addAll(toWatch, JuliaAddon.this.addonClass.getMethods());
|
Collections.addAll(toWatch, JuliaAddon.this.addonClass.getMethods());
|
||||||
for (Class<?> clazz : JuliaAddon.this.addon.searchPath())
|
for (Class<?> clazz : JuliaAddon.this.addon.filles())
|
||||||
try {
|
try {
|
||||||
Collections.addAll(toWatch, loadClass(clazz.getName()).getMethods());//loadClass(clazz.getName()) poir eviter les references cassees par les classloaders
|
Collections.addAll(toWatch, loadClass(clazz.getName()).getMethods());//loadClass(clazz.getName()) poir eviter les references cassees par les classloaders
|
||||||
} catch (SecurityException | ClassNotFoundException e) {
|
} catch (SecurityException | ClassNotFoundException e) {
|
||||||
e.printStackTrace();
|
erreur("L'addon "+JuliaAddon.this.addonClass.getName()+" spécifie la classe "+clazz.getName(),e);
|
||||||
System.err.println("L'addon "+JuliaAddon.this.addonClass.getName()+" spécifie la classe "+clazz.getName());
|
|
||||||
}
|
}
|
||||||
for(Method m : toWatch) {
|
for(Method m : toWatch) {
|
||||||
Command c = m.getAnnotation(Command.class);
|
Commande c = m.getAnnotation(Commande.class);
|
||||||
Discord d = m.getAnnotation(Discord.class);
|
EventDiscord d = m.getAnnotation(EventDiscord.class);
|
||||||
if(c != null) {
|
if(c != null) {
|
||||||
registeredCommands.add(m);
|
commandesEnregistrees.add(m);
|
||||||
laboratory.registerCommand(m, c);
|
laboratoire.enregistrerCommande(m, c);
|
||||||
}else if(d != null) {
|
}else if(d != null) {
|
||||||
registeredEvents.add(m);
|
eventsEnregistrees.add(m);
|
||||||
laboratory.registerEvent(m, d);
|
laboratoire.enregistrerEvent(m, d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterCommandsAndEvents() {
|
/**
|
||||||
for(Method m : registeredCommands) {
|
* Désenregistre du laboratoire associé toutes les commandes et les
|
||||||
Command c = m.getAnnotation(Command.class);
|
* events présents dans les classes de ce classloader.
|
||||||
registeredCommands.add(m);
|
*/
|
||||||
laboratory.unregisterCommand(m, c);
|
public void desenregistrerCommandesEtEvents() {
|
||||||
|
for(Method m : commandesEnregistrees) {
|
||||||
|
Commande c = m.getAnnotation(Commande.class);
|
||||||
|
commandesEnregistrees.add(m);
|
||||||
|
laboratoire.desenregistrerCommande(c);
|
||||||
}
|
}
|
||||||
for(Method m : registeredEvents) {
|
for(Method m : eventsEnregistrees) {
|
||||||
Discord d = m.getAnnotation(Discord.class);
|
eventsEnregistrees.add(m);
|
||||||
registeredEvents.add(m);
|
laboratoire.desenregistrerEvent(m);
|
||||||
laboratory.unregisterEvent(m, d);
|
|
||||||
}
|
}
|
||||||
registeredCommands.clear();
|
commandesEnregistrees.clear();
|
||||||
registeredEvents.clear();
|
eventsEnregistrees.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère l'addon pour lequel est créé ce classloader.
|
||||||
|
*/
|
||||||
public JuliaAddon getAddon() {
|
public JuliaAddon getAddon() {
|
||||||
return JuliaAddon.this;
|
return JuliaAddon.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Method> getCommandesEnregistrees() {
|
||||||
|
return commandesEnregistrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Method> getEventsEnregistrees() {
|
||||||
|
return eventsEnregistrees;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class JarWithMultipleAddonsException extends Exception{
|
/**
|
||||||
|
* Une exception trahissant plusieurs addons dans un jeu d'entrées jar.
|
||||||
|
*
|
||||||
|
* L'exception contient des données qui devraient suffire à sélectionner de manière
|
||||||
|
* plus judicieuse les entrées afin d'eviter le problème.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static final class JarAuxMultiplesAddonsException extends Exception{
|
||||||
|
|
||||||
private static final long serialVersionUID = -7557959851687207287L;
|
private static final long serialVersionUID = -7557959851687207287L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partition des entrées qui devrait séparer correctement les addons
|
||||||
|
*/
|
||||||
Set<Set<JarEntry>> addonsEntries;
|
Set<Set<JarEntry>> addonsEntries;
|
||||||
|
|
||||||
public JarWithMultipleAddonsException(Set<Set<JarEntry>> addonsEntries) {
|
public JarAuxMultiplesAddonsException(Set<Set<JarEntry>> addonsEntries) {
|
||||||
this.addonsEntries = addonsEntries;
|
this.addonsEntries = addonsEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Set<JarEntry>> getAddonsEntries() {
|
public Set<Set<JarEntry>> entreesDeLAddon() {
|
||||||
return addonsEntries;
|
return addonsEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class DummyLaboratory extends Julia.Laboratory{
|
/**
|
||||||
|
* Un laboratoire factice prévu pour observer les fichier jar sans les enregistrer nul part.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static final class LaboFactice extends Julia.Laboratoire{
|
||||||
|
|
||||||
public DummyLaboratory() {
|
public LaboFactice() {
|
||||||
Julia.theJulia().super(Character.MIN_VALUE);
|
Julia.theJulia().super("");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return pkg + ":" + version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
package com.bernard.juliabot;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
import net.dv8tion.jda.api.MessageBuilder;
|
|
||||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
|
||||||
|
|
||||||
public class JuliaErrPrintStream extends OutputStream {
|
|
||||||
|
|
||||||
StringBuilder tas = new StringBuilder(2000);// Les 2000 caractères de Discord
|
|
||||||
|
|
||||||
Lock cadenas;
|
|
||||||
|
|
||||||
MessageChannel logChannel;
|
|
||||||
|
|
||||||
public static final int maxlength = 1900;
|
|
||||||
|
|
||||||
public JuliaErrPrintStream(MessageChannel logChan) {
|
|
||||||
this.cadenas = new ReentrantLock();
|
|
||||||
this.logChannel = logChan;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(int i) throws IOException {
|
|
||||||
tas.append((char)(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void flushMessage() {
|
|
||||||
if(tas.length()==0)return;
|
|
||||||
this.cadenas.lock();
|
|
||||||
String str = tas.toString();
|
|
||||||
for(int i = 0; i*maxlength < tas.length();i++) {
|
|
||||||
MessageBuilder builder = new MessageBuilder();
|
|
||||||
builder.appendCodeBlock(str.substring(i*maxlength, Math.min((i+1)*maxlength,tas.length())), "");
|
|
||||||
logChannel.sendMessage(builder.build()).queue();
|
|
||||||
}
|
|
||||||
tas = new StringBuilder();
|
|
||||||
this.cadenas.unlock();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintStream ps = null;
|
|
||||||
public PrintStream printStream() {
|
|
||||||
if(ps == null)
|
|
||||||
ps = new PrintStream(this);
|
|
||||||
return ps;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
184
src/main/java/com/bernard/juliabot/PrintStreamDiscord.java
Normal file
184
src/main/java/com/bernard/juliabot/PrintStreamDiscord.java
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
package com.bernard.juliabot;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
import net.dv8tion.jda.api.MessageBuilder;
|
||||||
|
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream de caractères dirigé vers un canal discord.
|
||||||
|
*
|
||||||
|
* Les utilisateurs doivent appller flushMessage() afin que soit envoyé le message.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PrintStreamDiscord extends OutputStream {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Un buffer stoquant les prochains caractères à afficher.
|
||||||
|
*/
|
||||||
|
StringBuilder tas = new StringBuilder(2000);// Les 2000 caractères de Discord
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cadenas bloquant le write pendant la création du message discord.
|
||||||
|
*/
|
||||||
|
Lock cadenas;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le channel dans lequel envoyer tous les caractères.
|
||||||
|
*/
|
||||||
|
MessageChannel logChannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* La longueur maximale d'un message sur discord.
|
||||||
|
*/
|
||||||
|
public static final int maxlength = 1900;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un canal dirigé vers le canal spécifié.
|
||||||
|
* @param logChan Un channel discord pour lequel julia à un accès en écriture.
|
||||||
|
*/
|
||||||
|
public PrintStreamDiscord(MessageChannel logChan) {
|
||||||
|
this.cadenas = new ReentrantLock();
|
||||||
|
this.logChannel = logChan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int i) throws IOException {
|
||||||
|
cadenas.lock();
|
||||||
|
try {
|
||||||
|
tas.append((char)(i));
|
||||||
|
} finally {cadenas.unlock();}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoie le buffer dans le salon discord.
|
||||||
|
*/
|
||||||
|
public synchronized void flushMessage() {
|
||||||
|
if(tas.length()==0)return;
|
||||||
|
this.cadenas.lock();
|
||||||
|
String str = tas.toString();
|
||||||
|
for(int i = 0; i*maxlength < tas.length();i++) {
|
||||||
|
MessageBuilder builder = new MessageBuilder();
|
||||||
|
builder.appendCodeBlock(str.substring(i*maxlength, Math.min((i+1)*maxlength,tas.length())), "");
|
||||||
|
logChannel.sendMessage(builder.build()).queue();
|
||||||
|
}
|
||||||
|
tas = new StringBuilder();
|
||||||
|
this.cadenas.unlock();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Une instance de printstream sauvegardée.
|
||||||
|
*/
|
||||||
|
PrintStream ps = null;
|
||||||
|
/**
|
||||||
|
* Crée si besoin une seule fois un PrintStream écrivant dans cet OutputStream.
|
||||||
|
*/
|
||||||
|
public PrintStream printStream() {
|
||||||
|
if(ps == null)
|
||||||
|
ps = new PrintStream(this);
|
||||||
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoie un message découpé en blocs dans le canal spécifié.
|
||||||
|
* Le message sera découpé en élements d'à peu près la taille max de message.
|
||||||
|
* @param message Le message à écrire, potentiellement long.
|
||||||
|
* @param logChannel Le canal de sortie.
|
||||||
|
*/
|
||||||
|
public static void logErrMessage(String message, MessageChannel logChannel) {
|
||||||
|
for(int i = 0; i*maxlength < message.length();i++) {
|
||||||
|
MessageBuilder builder = new MessageBuilder();
|
||||||
|
builder.appendCodeLine(message.substring(i*maxlength, Math.min((i+1)*maxlength,message.length())));
|
||||||
|
logChannel.sendMessage(builder.build()).queue();
|
||||||
|
builder = new MessageBuilder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Envoie le message découpé en blocs dans le canal d'erreur de ce PrintStream.
|
||||||
|
* @param message Le message, potentiellement long, à afficher.
|
||||||
|
*/
|
||||||
|
public void errMessage(String message) {
|
||||||
|
logErrMessage(message, logChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log l'erreur d'entrée dans le canal spécifié. Le message est affiché en premier en texte
|
||||||
|
* brut, puis le Throwable est ensuite affiché dans un ou plusieurs blocs suivant sa taille.
|
||||||
|
* @param message Le message décrivant le contexte de l'erreur
|
||||||
|
* @param error L'erreur en elle-même
|
||||||
|
* @param logChannel Le canal dans lequel afficher l'erreur.
|
||||||
|
*/
|
||||||
|
public static void logErrMessageAndThrowable(String message, Throwable error, MessageChannel logChannel) {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
error.printStackTrace(new PrintWriter(sw));
|
||||||
|
String errMessage = sw.toString();
|
||||||
|
|
||||||
|
if(errMessage.length()+message.length()+1<maxlength) {
|
||||||
|
MessageBuilder builder = new MessageBuilder();
|
||||||
|
|
||||||
|
builder.appendCodeLine(message);
|
||||||
|
builder.append('\n');
|
||||||
|
builder.appendCodeBlock(errMessage, "");
|
||||||
|
logChannel.sendMessage(builder.build()).queue();
|
||||||
|
|
||||||
|
}else {
|
||||||
|
Julia.theJulia().realErr().println("Leeeeeee Bricoleur");
|
||||||
|
// On doit faire du découpage.
|
||||||
|
String[] nommes = errMessage.split("\n");
|
||||||
|
MessageBuilder builder = new MessageBuilder();
|
||||||
|
builder.appendCodeLine(message);
|
||||||
|
builder.append('\n');
|
||||||
|
int depassement = message.length()+1;
|
||||||
|
StringBuilder reste = new StringBuilder();
|
||||||
|
for(String nm : nommes) {
|
||||||
|
if(depassement+nm.length()>=maxlength) {
|
||||||
|
// On envoie maintenant
|
||||||
|
builder.appendCodeBlock(reste.toString(), "");
|
||||||
|
logChannel.sendMessage(builder.build()).queue();
|
||||||
|
builder = new MessageBuilder();
|
||||||
|
reste = new StringBuilder();
|
||||||
|
depassement = 0;
|
||||||
|
}
|
||||||
|
if(nm.length() >= maxlength) { // Reste est nécessairement vide
|
||||||
|
// Pas le choix que d'envoyer avec découpage dégueulasse.
|
||||||
|
for(int i = 0; i*maxlength < nm.length();i++) {
|
||||||
|
builder.appendCodeBlock(nm.substring(i*maxlength, Math.min((i+1)*maxlength,nm.length())), "");
|
||||||
|
logChannel.sendMessage(builder.build()).queue();
|
||||||
|
builder = new MessageBuilder();
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
reste.append(nm+"\n");
|
||||||
|
depassement += nm.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.appendCodeBlock(reste.toString(), "");
|
||||||
|
logChannel.sendMessage(builder.build()).queue();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log l'erreur d'entrée dans le canal de ce PrintStream. Le message est affiché en premier en texte
|
||||||
|
* brut, puis le Throwable est ensuite affiché dans un ou plusieurs blocs suivant sa taille.
|
||||||
|
* @param message Le message décrivant le contexte de l'erreur.
|
||||||
|
* @param error L'erreur en elle-même.
|
||||||
|
*/
|
||||||
|
public void errMessageAndThrowable(String message, Throwable error) {
|
||||||
|
logErrMessageAndThrowable(message, error, logChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
package com.bernard.juliabot.api;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Décrit des arguments bash d'une commande type bash.
|
||||||
|
*
|
||||||
|
* La commande est séparée en nommes, arguments et flags, ces deux derniers étant
|
||||||
|
* indépendant de leur position.
|
||||||
|
*
|
||||||
|
* Exemple: commande nomme1 nomme2 --flag1 --flag2 --arg1=val1 nomme3 --arg2=val2 --flag3
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ArgumentsComplexes {
|
||||||
|
|
||||||
|
List<String> nommes;
|
||||||
|
Map<String,String> arguments;
|
||||||
|
Set<String> flags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise cet argument avec les paramètres indiqués.
|
||||||
|
* @param nommes Les nommes, ordonnés de la commande
|
||||||
|
* @param arguments Map qui à chaque argument associe sa valeur.
|
||||||
|
* @param flags Ensemble non ordonné des flags.
|
||||||
|
*/
|
||||||
|
public ArgumentsComplexes(List<String> nommes, Map<String, String> arguments, Set<String> flags) {
|
||||||
|
this.nommes = nommes;
|
||||||
|
this.arguments = arguments;
|
||||||
|
this.flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie la liste ordonnée des nommes.
|
||||||
|
* @return Liste des nommes.
|
||||||
|
*/
|
||||||
|
public List<String> getNommes() {
|
||||||
|
return Collections.unmodifiableList(nommes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie une map qui à chaque argument spécifié associe sa valeur.
|
||||||
|
* @return La map des arguments.
|
||||||
|
*/
|
||||||
|
public Map<String, String> getArguments() {
|
||||||
|
return Collections.unmodifiableMap(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie l'ensemble des flags spécifiés.
|
||||||
|
* @return L'ensemble des flags.
|
||||||
|
*/
|
||||||
|
public Set<String> getFlags() {
|
||||||
|
return Collections.unmodifiableSet(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie true si et seulement si le flag donné en paramètre a été spécifié.
|
||||||
|
* @param flag le flag a tester
|
||||||
|
* @return true ssi flag est spécifié.
|
||||||
|
*/
|
||||||
|
public boolean hasFlag(String flag) {
|
||||||
|
return flags.contains(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie la valeur associée à l'argument «name», et null si l'argument n'a pas été spécifié.
|
||||||
|
* @param name le nom de l'argument.
|
||||||
|
* @return La valeur de l'argument ou null.
|
||||||
|
*/
|
||||||
|
public String getArgument(String name) {
|
||||||
|
return arguments.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie le n-ième nomme de la commande, le 0ème nomme correspondant typiquement au nom
|
||||||
|
* de la commande elle-même.
|
||||||
|
* @param pos L'indice du nomme.
|
||||||
|
* @return La valeur du nomme.
|
||||||
|
*/
|
||||||
|
public String getNomme(int pos) {
|
||||||
|
return nommes.get(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie le nombre de nommes de la commande, utile pour tester si tous ont été spécifiés.
|
||||||
|
* @return Le nombre de nommes.
|
||||||
|
*/
|
||||||
|
public int getNommeCount() {
|
||||||
|
return nommes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,9 +1,16 @@
|
|||||||
package com.bernard.juliabot.api;
|
package com.bernard.juliabot.api;
|
||||||
|
|
||||||
import com.bernard.juliabot.Julia.Laboratory;
|
/**
|
||||||
|
* Une super-interface décrivant les capacités d'une requête recue.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
public interface CCommande {
|
public interface CCommande {
|
||||||
|
|
||||||
public Laboratory getLabo();
|
/**
|
||||||
|
* L'ID du laboratoire dans lequel a été lancé la commande
|
||||||
|
* @return La chaine de caractère de l'ID
|
||||||
|
*/
|
||||||
|
public String getLaboId();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
60
src/main/java/com/bernard/juliabot/api/CCommandeDiscord.java
Normal file
60
src/main/java/com/bernard/juliabot/api/CCommandeDiscord.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package com.bernard.juliabot.api;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
|
import net.dv8tion.jda.api.JDA;
|
||||||
|
import net.dv8tion.jda.api.entities.Message;
|
||||||
|
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||||
|
import net.dv8tion.jda.api.entities.User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Une CCommande décrivant une requète/commande envoyée depuis un message Discord.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface CCommandeDiscord extends CCommandeString {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie le message qui a créé cette requête, tel que récupéré par la JDA.
|
||||||
|
*
|
||||||
|
* La consistance du message n'est pas assurée.
|
||||||
|
* @return Le message à l'origine de la requête.
|
||||||
|
*/
|
||||||
|
public Message getMessage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie le canal dans lequel la requête a été formulée, tel que récupéré du JDA.
|
||||||
|
*
|
||||||
|
* La consistance du channel n'est pas assurée.
|
||||||
|
* @return Le canal de formulation de la requête.
|
||||||
|
*/
|
||||||
|
public MessageChannel getChannel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie l'utilisateur ayant formulé cette requête, tel que récupéré par la JDA.
|
||||||
|
*
|
||||||
|
* La consistance de l'user n'est pas assurée.
|
||||||
|
* @return L'utilisateur à l'origine de la requête.
|
||||||
|
*/
|
||||||
|
public User getUser();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie la JDA qui a détécté l'évenement.
|
||||||
|
*
|
||||||
|
* @return La JDA initiante.
|
||||||
|
*/
|
||||||
|
public JDA getJDA();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie le contenu original du message ayant créé la requête.
|
||||||
|
* @return Le texte retiré de ses effets de style (markdown).
|
||||||
|
*/
|
||||||
|
public String getContentStripped();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie la date de récéption du message.
|
||||||
|
* @return La date de récéption du message.
|
||||||
|
*/
|
||||||
|
public OffsetDateTime getPostDate();
|
||||||
|
|
||||||
|
}
|
||||||
23
src/main/java/com/bernard/juliabot/api/CCommandeString.java
Normal file
23
src/main/java/com/bernard/juliabot/api/CCommandeString.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package com.bernard.juliabot.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Une CCommande décrite par une chaine de caractères.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface CCommandeString extends CCommande{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* La chaine de caractères décrivant la commande.
|
||||||
|
* @return La chaine sus-nommée.
|
||||||
|
*/
|
||||||
|
public String getStringCommand();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie les arguments complèxes associés à cette chaine de caractères.
|
||||||
|
* L'objet renvoyé peut être toujours le même ou généré à chaque fois.
|
||||||
|
* @return Les arguments complexes récupérés de la chaine de la commande.
|
||||||
|
*/
|
||||||
|
public ArgumentsComplexes getArguments();
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,15 +0,0 @@
|
|||||||
package com.bernard.juliabot.api;
|
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
|
||||||
|
|
||||||
@Target(value = ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface Command {
|
|
||||||
|
|
||||||
public String name();
|
|
||||||
public String[] aliases() default {};
|
|
||||||
public String description();
|
|
||||||
public String synopsis() default "";
|
|
||||||
public boolean admin();//TODO a remplacer par les permissions
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
package com.bernard.juliabot.api;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class CommandArguments {
|
|
||||||
|
|
||||||
List<String> nommes;
|
|
||||||
Map<String,String> arguments;
|
|
||||||
Set<String> flags;
|
|
||||||
|
|
||||||
public CommandArguments(List<String> nommes, Map<String, String> arguments, Set<String> flags) {
|
|
||||||
this.nommes = nommes;
|
|
||||||
this.arguments = arguments;
|
|
||||||
this.flags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getNommes() {
|
|
||||||
return nommes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getArguments() {
|
|
||||||
return arguments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getFlags() {
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasTag(String tag) {
|
|
||||||
return flags.contains(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getArgument(String name) {
|
|
||||||
return arguments.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNomme(int pos) {
|
|
||||||
return nommes.get(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNommeCount() {
|
|
||||||
return nommes.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
41
src/main/java/com/bernard/juliabot/api/Commande.java
Normal file
41
src/main/java/com/bernard/juliabot/api/Commande.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package com.bernard.juliabot.api;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation à appliquer à une méthode afin qu'elle réagisse aux commandes
|
||||||
|
* envoyées sur discord ou via le sysin.
|
||||||
|
*
|
||||||
|
* Tous les arguments de la méthodes doivent étendre
|
||||||
|
* {@link com.bernard.juliabot.api.CCommande}.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Target(value = ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Commande {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le nom de la commande. Doit être à peu prêt unique, les nom plus
|
||||||
|
* «communs» doivent être mis dans les alias.
|
||||||
|
*/
|
||||||
|
public String name();
|
||||||
|
/**
|
||||||
|
* Tableau des alias possible de la commande, c'est moins grâve si
|
||||||
|
* il y a des doublons.
|
||||||
|
*/
|
||||||
|
public String[] alias() default {};
|
||||||
|
/**
|
||||||
|
* Une description d'une ligne environ de la commande, explique son effet.
|
||||||
|
*/
|
||||||
|
public String description();
|
||||||
|
/**
|
||||||
|
* Le synopsis de la commande dans un style proche des pages man.
|
||||||
|
*/
|
||||||
|
public String synopsis() default "";
|
||||||
|
/**
|
||||||
|
* true si la commande ne peut être éxecutée que par des admins.
|
||||||
|
*/
|
||||||
|
public boolean admin() default false;//TODO a remplacer par les permissions
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.bernard.juliabot.api;
|
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
|
||||||
|
|
||||||
@Target(value = ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface Discord {
|
|
||||||
|
|
||||||
public String description();
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package com.bernard.juliabot.api;
|
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
|
|
||||||
import net.dv8tion.jda.api.JDA;
|
|
||||||
import net.dv8tion.jda.api.entities.Message;
|
|
||||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
|
||||||
import net.dv8tion.jda.api.entities.User;
|
|
||||||
|
|
||||||
public interface DiscordCCommande extends StringCCommande {
|
|
||||||
|
|
||||||
public Message getMessage();
|
|
||||||
|
|
||||||
public MessageChannel getChannel();
|
|
||||||
|
|
||||||
public User getUser();
|
|
||||||
|
|
||||||
public JDA getJDA();
|
|
||||||
|
|
||||||
public String getContentStripped();
|
|
||||||
|
|
||||||
public OffsetDateTime getPostDate();
|
|
||||||
|
|
||||||
}
|
|
||||||
20
src/main/java/com/bernard/juliabot/api/EventDiscord.java
Normal file
20
src/main/java/com/bernard/juliabot/api/EventDiscord.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package com.bernard.juliabot.api;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation à appliquer à une méthode pour indiquer qu'elle doit
|
||||||
|
* être appelée lorsque la JDA recoit des évenements (et que ces évenements sont
|
||||||
|
* bien destinés au bon laboratoire).
|
||||||
|
*
|
||||||
|
* Les méthodes doivent avoir un unique argument qui étende
|
||||||
|
* {@link net.dv8tion.jda.api.events.GenericEvent}.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Target(value = ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface EventDiscord {
|
||||||
|
public String description();
|
||||||
|
|
||||||
|
}
|
||||||
69
src/main/java/com/bernard/juliabot/api/Julia.java
Normal file
69
src/main/java/com/bernard/juliabot/api/Julia.java
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package com.bernard.juliabot.api;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
|
||||||
|
import com.bernard.juliabot.PrintStreamDiscord;
|
||||||
|
import static com.bernard.juliabot.Julia.theJulia;
|
||||||
|
|
||||||
|
import net.dv8tion.jda.api.JDA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anciennement appelée Trukilie, permet d'interragir avec Julia avec uniquement
|
||||||
|
* des appels statics, et donc depuis n'importe où dans le programme.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Julia {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accès au JDA initialisé par Julia.
|
||||||
|
* @return La JDA.
|
||||||
|
*/
|
||||||
|
public static JDA jda() {
|
||||||
|
return theJulia().getJda();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère la connection SQL à la base de données.
|
||||||
|
*
|
||||||
|
* Prévu pour que les juliaddons accèdent à leurs données.
|
||||||
|
* @return Une connection normalement ouverte.
|
||||||
|
*/
|
||||||
|
public static Connection juliaBDD() {
|
||||||
|
return theJulia().getJuliaBDD();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoie un message dans sysout et dans le canal «status» du Discord
|
||||||
|
* @param message Le message à envoyer, optimalement d'une seule ligne et assez court.
|
||||||
|
*/
|
||||||
|
public static void status(String message) {
|
||||||
|
System.out.println(message);
|
||||||
|
|
||||||
|
PrintStreamDiscord.logErrMessage(message, theJulia().statusTextChannel());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoie un message dans le syserr et dans le canal d'erreur du Discord
|
||||||
|
* @param message Le message décrivant l'erreur, optimalement d'une seule ligne et assez court.
|
||||||
|
*/
|
||||||
|
public static void erreur(String message) {
|
||||||
|
theJulia().realErr().println(message);
|
||||||
|
|
||||||
|
if(theJulia().getSyserr() != null)
|
||||||
|
theJulia().getSyserr().errMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoie un message d'erreur avec un stacktrace dans le syserr et dans le canal d'erreur du Discord.
|
||||||
|
* @param message Le message décrivant l'erreur, optimalement d'une seule ligne et assez court.
|
||||||
|
* @param error L'erreur qui sera écrite à la suite du message, avec son stacktrace.
|
||||||
|
*/
|
||||||
|
public static void erreur(String message, Throwable error) {
|
||||||
|
theJulia().realErr().println(message);
|
||||||
|
error.printStackTrace(theJulia().realErr());
|
||||||
|
|
||||||
|
theJulia().getSyserr().errMessageAndThrowable(message, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,40 +0,0 @@
|
|||||||
package com.bernard.juliabot.api;
|
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import com.bernard.juliabot.Julia;
|
|
||||||
|
|
||||||
public class JuliaConfig {
|
|
||||||
|
|
||||||
public static final String get(String name) {
|
|
||||||
try {
|
|
||||||
PreparedStatement st = Julia.theJulia().getJuliaDatabase().prepareStatement("SELECT * FROM juliaConfig WHERE strID=?");
|
|
||||||
st.setString(1, name);
|
|
||||||
ResultSet r = st.executeQuery();
|
|
||||||
if(r.getFetchSize() == 0)
|
|
||||||
throw new IllegalArgumentException("La configuration "+name+" n'existe pas ... veuillez la rentrer avant de la demander");
|
|
||||||
String value = r.getString("value");
|
|
||||||
return value;
|
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new IllegalStateException("Impossible de faire des requetes à la bdd de julia. Est-elle initialisée au moins ?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final void set(String name, String value) {
|
|
||||||
try {
|
|
||||||
PreparedStatement st = Julia.theJulia().getJuliaDatabase().prepareStatement("UPDATE juliaConfig SET value=? WHERE strID=?");
|
|
||||||
st.setString(1, value);
|
|
||||||
st.setString(2, value);
|
|
||||||
int r = st.executeUpdate();
|
|
||||||
if(r == 0)
|
|
||||||
throw new IllegalArgumentException("La configuration "+name+" n'a pas pu être modifiée ... existe-elle ?");
|
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new IllegalStateException("Impossible de faire des requetes à la bdd de julia. Est-elle initialisée au moins ?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -7,22 +7,31 @@ import java.lang.annotation.Documented;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation à appliquer à une classe principale d'un Juliaddon.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
@Documented
|
@Documented
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
@Target(TYPE)
|
@Target(TYPE)
|
||||||
public @interface JuLIAddon {
|
public @interface Juliaddon {
|
||||||
/**
|
/**
|
||||||
* Le nom de l'addon
|
* Le nom de l'addon
|
||||||
*/
|
*/
|
||||||
String name();
|
String nom();
|
||||||
/**
|
/**
|
||||||
* La version de l'addon
|
* La version de l'addon
|
||||||
|
*
|
||||||
|
* Par défaut: La version spécifiée dans le nom du fichier de l'addon sera utilisé.
|
||||||
*/
|
*/
|
||||||
String version() default "";
|
String version() default "";
|
||||||
/**
|
/**
|
||||||
* Différentes classes, en plus de celle là, dans laquelle chercher des méthodes définissant des événements ou des commandes
|
* Différentes classes, en plus de celle là, dans laquelle chercher des méthodes définissant des événements ou des commandes
|
||||||
|
*
|
||||||
|
* Par défaut: Aucune fille, donc uniquement cette classe.
|
||||||
*/
|
*/
|
||||||
Class<?>[] searchPath() default {};
|
Class<?>[] filles() default {};
|
||||||
/**
|
/**
|
||||||
* La liste des personnes ayant dévellopé cet addon
|
* La liste des personnes ayant dévellopé cet addon
|
||||||
*/
|
*/
|
||||||
@ -1,9 +0,0 @@
|
|||||||
package com.bernard.juliabot.api;
|
|
||||||
|
|
||||||
public interface StringCCommande extends CCommande{
|
|
||||||
|
|
||||||
public String getStringCommand();
|
|
||||||
|
|
||||||
public CommandArguments getArguments();
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
package com.bernard.juliabot.api;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
|
|
||||||
import com.bernard.juliabot.Julia;
|
|
||||||
|
|
||||||
import net.dv8tion.jda.api.JDA;
|
|
||||||
|
|
||||||
public class Trukilie {
|
|
||||||
|
|
||||||
public static JDA jda() {
|
|
||||||
return Julia.theJulia().getJda();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Connection juliaDB() {
|
|
||||||
return Julia.theJulia().getJuliaDatabase();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,60 +1,92 @@
|
|||||||
package com.bernard.juliabot.internaddon;
|
package com.bernard.juliabot.internaddon;
|
||||||
|
|
||||||
|
import static com.bernard.juliabot.api.Julia.erreur;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import com.bernard.juliabot.CommandCalled;
|
import org.simmetrics.StringDistance;
|
||||||
|
import org.simmetrics.metrics.StringDistances;
|
||||||
|
|
||||||
|
import com.bernard.juliabot.AppelACommande;
|
||||||
|
import com.bernard.juliabot.CommandeSurchargee;
|
||||||
import com.bernard.juliabot.Julia;
|
import com.bernard.juliabot.Julia;
|
||||||
import com.bernard.juliabot.Julia.Laboratory;
|
import com.bernard.juliabot.Julia.Laboratoire;
|
||||||
import com.bernard.juliabot.JuliaAddon;
|
import com.bernard.juliabot.JuliaAddon;
|
||||||
import com.bernard.juliabot.api.Command;
|
import com.bernard.juliabot.JuliaAddon.JuliaClassLoader;
|
||||||
import com.bernard.juliabot.api.CommandArguments;
|
import com.bernard.juliabot.api.ArgumentsComplexes;
|
||||||
import com.bernard.juliabot.api.Discord;
|
import com.bernard.juliabot.api.CCommandeDiscord;
|
||||||
import com.bernard.juliabot.api.DiscordCCommande;
|
import com.bernard.juliabot.api.CCommandeString;
|
||||||
import com.bernard.juliabot.api.JuLIAddon;
|
import com.bernard.juliabot.api.Commande;
|
||||||
import com.bernard.juliabot.api.StringCCommande;
|
import com.bernard.juliabot.api.EventDiscord;
|
||||||
|
import com.bernard.juliabot.api.Juliaddon;
|
||||||
import com.thedeanda.lorem.LoremIpsum;
|
import com.thedeanda.lorem.LoremIpsum;
|
||||||
|
|
||||||
|
import net.dv8tion.jda.api.EmbedBuilder;
|
||||||
import net.dv8tion.jda.api.JDA;
|
import net.dv8tion.jda.api.JDA;
|
||||||
import net.dv8tion.jda.api.MessageBuilder;
|
import net.dv8tion.jda.api.MessageBuilder;
|
||||||
|
import net.dv8tion.jda.api.entities.GuildChannel;
|
||||||
import net.dv8tion.jda.api.entities.Message;
|
import net.dv8tion.jda.api.entities.Message;
|
||||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||||
|
import net.dv8tion.jda.api.entities.MessageEmbed;
|
||||||
import net.dv8tion.jda.api.entities.User;
|
import net.dv8tion.jda.api.entities.User;
|
||||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||||
|
import net.dv8tion.jda.api.requests.restaction.MessageAction;
|
||||||
|
import net.dv8tion.jda.internal.utils.tuple.Pair;
|
||||||
|
|
||||||
@JuLIAddon(name="internaddon", devs = "Bernard", version="beta")
|
/**
|
||||||
|
* Cet addon est chargé de force dans chaque laboratoire. Il est celui qui permet de charger/décharger
|
||||||
|
* les autres addons et surtout de comprendre les commandes depuis les events reçus.
|
||||||
|
*
|
||||||
|
* Cet addon est fait pour être le seul qui accède directement aux méthodes de {@link com.bernard.juliabot.Julia}, sans
|
||||||
|
* passer par {@link com.bernard.juilabot.api.Julia}.
|
||||||
|
* @author mysaa
|
||||||
|
*/
|
||||||
|
@Juliaddon(nom="internaddon", devs = "Bernard", version="beta")
|
||||||
public class Internaddon {
|
public class Internaddon {
|
||||||
|
|
||||||
public static final String COMMANDEUR = "!!";
|
public static final String COMMANDEUR = "!!";
|
||||||
|
|
||||||
@Discord(description = "LE catcheur des commandes discords. Les messages recus sont lus puis executes ici si ce sont des commandes")
|
/**
|
||||||
public void getCommand(MessageReceivedEvent e) {
|
* Le catcheur d'evnts qui reconnais les commandes et demande à JuL'IA de les éxecuter.
|
||||||
|
*/
|
||||||
|
@EventDiscord(description = "LE catcheur des commandes discords. Les messages recus sont lus puis executes ici si ce sont des commandes")
|
||||||
|
public void getCommande(MessageReceivedEvent e) {
|
||||||
if(e.getMessage().getContentRaw().startsWith(COMMANDEUR)) {
|
if(e.getMessage().getContentRaw().startsWith(COMMANDEUR)) {
|
||||||
String name = e.getMessage().getContentRaw().split(" ")[0].substring(COMMANDEUR.length());
|
String nom = e.getMessage().getContentRaw().split(" ")[0].substring(COMMANDEUR.length());
|
||||||
|
|
||||||
Laboratory labo = Julia.theJulia().getLaboratoires().get(Julia.theJulia().getLecouteur().getLabo(e));//Récupére le labo de l'évent
|
Laboratoire labo = Julia.theJulia().getLecouteur().getLabo(e);//Récupére le labo de l'évent
|
||||||
InternalddonCCommande ccommande = new InternalddonCCommande(e,labo);
|
InternalddonCCommande ccommande = new InternalddonCCommande(e,labo);
|
||||||
try {
|
try {
|
||||||
CommandCalled called = labo.executeCommand(name, ccommande);
|
AppelACommande appelee = labo.executer(nom, ccommande);
|
||||||
System.out.println(called);
|
System.out.println(appelee);
|
||||||
}catch(IllegalArgumentException ex) {
|
}catch(IllegalArgumentException ex) {
|
||||||
// La commande n'existe pas
|
// La commande n'existe pas
|
||||||
e.getChannel().sendMessage("Moi pas connaitre `"+name+"`. Vous apprendre moi ?").queue();
|
e.getChannel().sendMessage("Moi pas connaitre `"+nom+"`. Vous apprendre moi ?").queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(name = "julia", aliases="juju", description = "Répond à l'appel", admin = true)
|
/**
|
||||||
public void julia(DiscordCCommande commande) {
|
* Une commande pour tester le ping de julia.
|
||||||
|
*/
|
||||||
|
@Commande(name = "julia", alias="juju", synopsis = "!!julia", description = "Répond à l'appel", admin = true)
|
||||||
|
public void julia(CCommandeDiscord commande) {
|
||||||
User user = commande.getUser();
|
User user = commande.getUser();
|
||||||
MessageChannel channel = commande.getChannel();
|
MessageChannel channel = commande.getChannel();
|
||||||
String[] julias = new String[]{"Présent !", "Présente !", "Présentbleu !", "Présentavion !", "Présent(e) !", "Présent(bleu) !",
|
String[] julias = new String[]{"Présent !", "Présente !", "Présentbleu !", "Présentavion !", "Présent(e) !", "Présent(bleu) !",
|
||||||
@ -65,63 +97,187 @@ public class Internaddon {
|
|||||||
String out = julias[(int)Math.floor(Math.random() * julias.length)];
|
String out = julias[(int)Math.floor(Math.random() * julias.length)];
|
||||||
channel.sendMessage(out).queue();
|
channel.sendMessage(out).queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final DateFormat addonFileTimeDf = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.FRANCE);
|
||||||
|
|
||||||
@Command(name = "help", aliases= {"ausecours","?","allahuakbar"}, description = "Laissez-vous aider par le meilleur bot du monde", admin = true)
|
/**
|
||||||
public void help(DiscordCCommande commande) {
|
* Liste les addons chargés ainsi que les commandes enregistrées.
|
||||||
StringBuilder s = new StringBuilder();
|
*/
|
||||||
s.append("```");
|
@Commande(name = "aide", alias= {"help","ausecours","?","allahuakbar"}, synopsis = "!!help [commandName | pkg] --labo=str", description = "Laissez-vous aider par le meilleur bot du monde", admin = true)
|
||||||
|
public void aide(CCommandeDiscord commande) {
|
||||||
|
ArgumentsComplexes args = commande.getArguments();
|
||||||
|
|
||||||
Laboratory l = commande.getLabo();
|
String lab = args.getArguments().getOrDefault("labo", commande.getLaboId());
|
||||||
s.append("Vous étes actuellement dans le laboratoire '"+l.getL()+"'\n");
|
|
||||||
s.append("Liste des addons chargés :\n");
|
Laboratoire l = Julia.theJulia().getLaboratoires().get(lab);
|
||||||
for(JuliaAddon e : l.getLoadedAddons().values())
|
EmbedBuilder msg = new EmbedBuilder();
|
||||||
s.append("\t- "+e.getName()+" en version "+e.getVersion()+"\n");
|
if(args.getNommeCount() == 1) {
|
||||||
s.append("\nListe des commandes chargées :\n");
|
// On veut décrire un laboratoire.
|
||||||
for(String c : l.getLoadedCommands().keySet()) {
|
|
||||||
s.append("\t- "+c);
|
msg.setTitle(String.format("Description du laboratoire «%s»", l.getL()));
|
||||||
String collected = l.getAliases().entrySet().stream()
|
|
||||||
.filter(e->e.getValue().equals(c))
|
for(JuliaAddon e : l.getAddonsCharges()) {
|
||||||
.map(Map.Entry::getKey)
|
String commandes = e.getLoader(l)
|
||||||
.collect(Collectors.joining(", "));
|
.getCommandesEnregistrees()
|
||||||
if(!collected.isEmpty())
|
.stream()
|
||||||
s.append(" a.k.a "+collected);
|
.map(m -> m.getAnnotation(Commande.class))
|
||||||
if(l.getLoadedCommands().get(c).getDesc() != null)
|
.map(c -> c.name())
|
||||||
s.append(" :\n\t\t"+l.getLoadedCommands().get(c).getDesc());
|
.collect(Collectors.joining("; "));
|
||||||
s.append('\n');
|
msg.addField(
|
||||||
|
String.format("%s en version %s (%s)",e.getNom(),e.getVersion(),e.getPkg()),
|
||||||
|
String.format("Liste des commandes disponibles: %s", commandes),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
} else if (args.getNommeCount() == 2) {
|
||||||
|
// Compréhension du premier argument das cet ordre:
|
||||||
|
// pkg > lastPkgName > commandName > alias > addon
|
||||||
|
|
||||||
|
String nom = args.getNomme(1);
|
||||||
|
String pkg = null;
|
||||||
|
CommandeSurchargee cs = null;
|
||||||
|
|
||||||
|
Set<String> pkgs = Julia.theJulia().pkgSet();
|
||||||
|
|
||||||
|
if(pkgs.contains(nom))
|
||||||
|
pkg=nom; // C'est déjà un pkg donc bon
|
||||||
|
else {
|
||||||
|
Optional<String> ops = pkgs.stream()
|
||||||
|
.filter(p -> p.toLowerCase(Locale.FRENCH).endsWith("."+nom.toLowerCase(Locale.FRENCH)))
|
||||||
|
.findAny();
|
||||||
|
if(ops.isPresent())
|
||||||
|
pkg = ops.get();
|
||||||
|
else {
|
||||||
|
// On teste une commande OU un alias.
|
||||||
|
cs = l.commandeAssociee(nom);
|
||||||
|
|
||||||
|
if(cs == null)
|
||||||
|
pkg = comprendreAddon(nom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// On a «parse» le premier argument.
|
||||||
|
|
||||||
|
if(pkg != null) {
|
||||||
|
// On veut décrire un package.
|
||||||
|
String pkgf = pkg;
|
||||||
|
Optional<JuliaAddon> addonO = l.getAddonsCharges()
|
||||||
|
.stream()
|
||||||
|
.filter(a -> a.getPkg().equals(pkgf))
|
||||||
|
.findAny();
|
||||||
|
if(addonO.isEmpty()) {
|
||||||
|
// L'addon n'est pas chargé dans le laboratoire.
|
||||||
|
repondre(commande, "Vous voulez de l'aide sur l'internaddon "+pkg+" mais "
|
||||||
|
+ "il n'est pas chargé dans ce laboratoire ...").complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JuliaAddon addon = addonO.get();
|
||||||
|
|
||||||
|
msg.setTitle(String.format("Description du juliaddon %s (%s)",addon.getNom(),addon.getPkg()));
|
||||||
|
msg.setDescription(String.format(
|
||||||
|
"Cet addon est chargé dans le laboratoire %s en version %s. "
|
||||||
|
+ "Il est extrait du fichier %s chargé pour la dernière fois %s",
|
||||||
|
l.getL(),addon.getVersion(),addon.getFichierJar().getName(), addonFileTimeDf.format(Date.from(Instant.ofEpochMilli(addon.getDerniereModif())))));
|
||||||
|
|
||||||
|
JuliaClassLoader loader = addon.getLoader(l);
|
||||||
|
|
||||||
|
for(Method m : loader.getEventsEnregistrees()) {
|
||||||
|
EventDiscord ed = m.getAnnotation(EventDiscord.class);
|
||||||
|
if(ed==null) {
|
||||||
|
erreur("Inconsistance dans le classLoader de l'addon "+addon+" : "
|
||||||
|
+ "la méthode "+m.getName()+" est enregistrée comme event.");
|
||||||
|
repondre(commande, "Une erreur de classes est survenue. Contactez un développeur du Julia.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.addField(
|
||||||
|
m.getName() ,
|
||||||
|
ed.description(),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.addBlankField(false);
|
||||||
|
|
||||||
|
for(Method m : loader.getCommandesEnregistrees()) {
|
||||||
|
Commande ed = m.getAnnotation(Commande.class);
|
||||||
|
if(ed==null) {
|
||||||
|
erreur("Inconsistance dans le classLoader de l'addon "+addon+" : "
|
||||||
|
+ "la méthode "+m.getName()+" est enregistrée comme commande");
|
||||||
|
repondre(commande, "Une erreur de classes est survenue. Contactez un développeur du Julia.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.addField(
|
||||||
|
(ed.alias().length==0)
|
||||||
|
? String.format("Commande %s", ed.name())
|
||||||
|
: String.format("Commande %s (alias %s)", ed.name(),String.join(" ou ",ed.alias())) ,
|
||||||
|
ed.description(),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else if (cs != null){
|
||||||
|
// On veut décrire une commande.
|
||||||
|
|
||||||
|
Method executeur = cs.getExecuteur(commande);
|
||||||
|
if(! (executeur.getDeclaringClass().getClassLoader() instanceof JuliaClassLoader)) {
|
||||||
|
repondre(commande, "Impossible de récupérer l'addon correspondant à cette commande !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JuliaAddon addon = ((JuliaClassLoader)executeur.getDeclaringClass().getClassLoader()).getAddon();
|
||||||
|
|
||||||
|
msg.setTitle("Commande "+cs.getCommande().name());
|
||||||
|
|
||||||
|
msg.setDescription(cs.getDesc());
|
||||||
|
|
||||||
|
msg.addField("Synopsis",cs.getCommande().synopsis()
|
||||||
|
+ (cs.getCommande().admin()?"\nCette commande requiert les droits d'administrateur.":""),false);
|
||||||
|
|
||||||
|
msg.addField("Addon",
|
||||||
|
String.format("Cette commande est décrite par l'addon %s en version %s décrit "
|
||||||
|
+ "dans le fichier %s à la date %s. La méthode à executer est la méthode %s "
|
||||||
|
+ "de la classe %s.", addon.getNom(),addon.getVersion(),addon.getFichierJar().getName(),
|
||||||
|
addonFileTimeDf.format(Date.from(Instant.ofEpochMilli(addon.getDerniereModif()))),executeur.getName(),executeur.getDeclaringClass().getName()),false);
|
||||||
|
|
||||||
|
if(cs.getCommande().alias().length != 0)
|
||||||
|
msg.addField("Aliases", String.join(", ", cs.getCommande().alias()), false);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// On a pas compris ce qui devait être décrit.
|
||||||
|
repondre(commande, "Je n'ai pas compris ce sur quoi je devais vous aider ...").complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.append("```");
|
|
||||||
|
|
||||||
commande.getChannel().sendMessage(s).queue();
|
//msg.setFooter("Réponse à "+authorName(commande));// -> C'est moche
|
||||||
|
|
||||||
|
repondre(commande, msg.build()).complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(name = "blabla", aliases= {}, description = "Pour vous prouver que je parle", admin = true)
|
/**
|
||||||
public void blabla(DiscordCCommande commande) {
|
* Fait que julia publie un gros bloc de texte de type Lorem ipsum.
|
||||||
|
*/
|
||||||
|
@Commande(name = "blabla", alias= {}, description = "Pour vous prouver que je parle", admin = true)//TODO ajouter des options peut-être.
|
||||||
|
public void blabla(CCommandeDiscord commande) {
|
||||||
Message m = commande.getMessage();
|
Message m = commande.getMessage();
|
||||||
m.getChannel().sendMessage("```"+LoremIpsum.getInstance().getWords(150, 200)+"```").queue();
|
m.getChannel().sendMessage("```"+LoremIpsum.getInstance().getWords(150, 200)+"```").queue();
|
||||||
m.delete();
|
m.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(name = "tuerBebePhoque", aliases= {}, description = "Pour votre plaisir", admin = true)
|
/**
|
||||||
public void tuerBebePhoque(DiscordCCommande commande) {
|
* Renvoie la photo d'un bébé phoque mort pour soulager les développeurs stréssés.
|
||||||
|
*/
|
||||||
|
@Commande(name = "tuerBebePhoque", alias= {}, description = "Pour votre plaisir", admin = true)//TODO remplir un peu cette méthode.
|
||||||
|
public void tuerBebePhoque(CCommandeDiscord commande) {
|
||||||
Message m = commande.getMessage();
|
Message m = commande.getMessage();
|
||||||
m.getChannel().sendMessage("http://toni.mi.free.fr/vanhebdo/actions/phoques/im_phoque_coupGourdinAssomme_Sang.jpg").queue();
|
m.getChannel().sendMessage("http://toni.mi.free.fr/vanhebdo/actions/phoques/im_phoque_coupGourdinAssomme_Sang.jpg").queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commande de test de la décomposition des commandes. //XXX: À supprimer
|
||||||
@Discord(description = "Arthur, par-ce que vous n'étes pas qu'une caricature")
|
* @see ArgumentsComplexes
|
||||||
public void shutUp(MessageReceivedEvent e) {
|
*/
|
||||||
if(e.getAuthor().getIdLong() == 187677269626585089L) {//Yukimyo = L'Orchidoclaste
|
@Commande(name = "args", description = "Décompose les messages à la Discord'", admin = true)
|
||||||
|
public void args(CCommandeDiscord commande) {
|
||||||
e.getChannel().sendMessage(e.getAuthor().getAsMention() +" dis du caca").queue();
|
ArgumentsComplexes ca = commande.getArguments();// Réparer la commande.
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Command(name = "args", description = "Décompose les messages à la Discord'", admin = true)
|
|
||||||
public void args(DiscordCCommande commande) {
|
|
||||||
CommandArguments ca = commande.getArguments();
|
|
||||||
|
|
||||||
StringBuilder s = new StringBuilder();
|
StringBuilder s = new StringBuilder();
|
||||||
s.append("```"+commande.getStringCommand()+"```");
|
s.append("```"+commande.getStringCommand()+"```");
|
||||||
@ -135,8 +291,11 @@ public class Internaddon {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(name="guilds", description = "Liste les guildes disponibles",admin=true)
|
/**
|
||||||
public void guilds(DiscordCCommande commande) {
|
* Liste les guildes auquel Julia à accès.
|
||||||
|
*/
|
||||||
|
@Commande(name="guildes", alias= {"guilds"}, description = "Liste les guildes disponibles",admin=true)
|
||||||
|
public void guildes(CCommandeDiscord commande) {
|
||||||
MessageBuilder mb = new MessageBuilder();
|
MessageBuilder mb = new MessageBuilder();
|
||||||
mb.append("Liste des serveurs :\n");
|
mb.append("Liste des serveurs :\n");
|
||||||
Julia.theJulia().getJda().getGuilds()
|
Julia.theJulia().getJda().getGuilds()
|
||||||
@ -146,64 +305,234 @@ public class Internaddon {
|
|||||||
commande.getChannel().sendMessage(mb.build()).complete();
|
commande.getChannel().sendMessage(mb.build()).complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(name="update",description = "Met a jour le dossier des addons",admin=true)
|
/**
|
||||||
public void update(StringCCommande commande) {
|
* Met à jour la liste des addons disponibles, en lisant le dossier juliaddons.
|
||||||
|
*/
|
||||||
|
@Commande(name="maj", alias= {"update","miseAJour"},description = "Met a jour le dossier des addons",admin=true)
|
||||||
|
public void maj(CCommandeString commande) {
|
||||||
|
|
||||||
Julia.theJulia().update();
|
Julia.theJulia().addonsMaj();
|
||||||
|
|
||||||
|
if(CCommandeDiscord.class.isInstance(commande.getClass()))
|
||||||
|
repondre((CCommandeDiscord)commande, "La liste des addons disponibles a été mise à jour.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(name="load",description = "Charge l'addon dans ce laboratoire",admin=true)
|
/**
|
||||||
public void load(DiscordCCommande commande) {
|
* Charge l'addon spécifié en ligne de commande dans le laboratoire d'appel.
|
||||||
|
*/
|
||||||
|
@Commande(name="charger", alias= {"load"}, description = "Charge l'addon dans ce laboratoire",admin=true)
|
||||||
|
public void charger(CCommandeDiscord commande) {
|
||||||
|
|
||||||
CommandArguments cc = commande.getArguments();
|
ArgumentsComplexes cc = commande.getArguments();
|
||||||
|
|
||||||
String addonName = cc.getNomme(1);
|
String lab = cc.getArguments().getOrDefault("labo", commande.getLaboId());
|
||||||
String version = cc.getNomme(2);
|
|
||||||
|
|
||||||
Laboratory l = commande.getLabo();
|
if(cc.getNommeCount()<2) {
|
||||||
|
repondre(commande, "Il vous faut préciser l'addon que vous voulez charger !").complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String addonPkg = comprendreAddon(cc.getNomme(1));
|
||||||
|
|
||||||
|
if(addonPkg == null) {
|
||||||
|
repondre(commande, String.format("Je ne trouve pas d'addon correspondant à «%s» ...", cc.getNomme(1))).complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String version = null;
|
||||||
|
if(cc.getNommeCount()<3)
|
||||||
|
version = Julia.theJulia().latest(addonPkg);
|
||||||
|
else
|
||||||
|
version = cc.getNomme(2);
|
||||||
|
|
||||||
|
if(! Julia.theJulia().checkVersion(addonPkg,version)) {
|
||||||
|
repondre(commande, "Je ne trouve pas la version "+version+" pour l'addon "+addonPkg).complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Laboratoire l = Julia.theJulia().getLaboratoires().get(lab);
|
||||||
|
|
||||||
String out = "Terminé avec succés";
|
|
||||||
try {
|
try {
|
||||||
l.loadAddon(addonName, version);
|
l.loadAddon(addonPkg, version);
|
||||||
}catch (Exception e) {
|
}catch (Exception e) {
|
||||||
out = "```"+e.getClass().toString()+"\n"+e.getMessage()+"```";
|
repondre(commande, "Impossible de charger l'addon spécifié ! Contactez un admin julia.").complete();
|
||||||
|
erreur("Tentative de chargement depuis l'internaddon", e);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
commande.getChannel().sendMessage(out);
|
|
||||||
|
repondre(commande, String.format("L'addon %s a été chargé dans sa version %s dans le laboratoire %s", addonPkg, version, lab)).complete();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(name="unload",description = "Décharge l'addon de ce laboratoire",admin=true)
|
/**
|
||||||
public void unload(DiscordCCommande commande) {
|
* Décharge l'addon spécifié du laboratoire d'appel.
|
||||||
|
*/
|
||||||
|
@Commande(name="decharger", alias= {"unload"}, description = "Décharge l'addon de ce laboratoire",admin=true)
|
||||||
|
public void decharger(CCommandeDiscord commande) {
|
||||||
|
|
||||||
CommandArguments cc = commande.getArguments();
|
ArgumentsComplexes cc = commande.getArguments();
|
||||||
|
|
||||||
String addonName = cc.getNomme(1);
|
String lab = cc.getArguments().getOrDefault("labo", commande.getLaboId());
|
||||||
|
|
||||||
|
if(cc.getNommeCount()<2) {
|
||||||
|
repondre(commande, "Il vous faut préciser l'addon que vous voulez charger !").complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String addonPkg = comprendreAddon(cc.getNomme(1));
|
||||||
|
|
||||||
|
|
||||||
|
Laboratoire l = Julia.theJulia().getLaboratoires().get(lab);
|
||||||
|
|
||||||
Laboratory l = commande.getLabo();
|
|
||||||
|
|
||||||
String out = "Terminé avec succés";
|
|
||||||
try {
|
try {
|
||||||
l.unloadAddon(addonName);
|
l.dechargerAddon(addonPkg);
|
||||||
}catch (Exception e) {
|
}catch (Exception e) {
|
||||||
out = "```"+e.getClass().toString()+"\n"+e.getMessage()+"```";
|
repondre(commande, "Impossible de décharger l'addon spécifié ! Contactez un admin julia.").complete();
|
||||||
|
erreur("Tentative de déchargement depuis l'internaddon", e);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
commande.getChannel().sendMessage(out);
|
|
||||||
|
repondre(commande, String.format("L'addon %s a été déchargé du laboratoire %s", addonPkg, lab)).complete();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(name="caca",description = "Déclanche une exception ... Faut bien tester, hein !",admin=true)
|
/**
|
||||||
public void caca(DiscordCCommande commande) {
|
* Décharge puis recharge l'addon du laboratoire spécifié.
|
||||||
|
*/
|
||||||
|
@Commande(name="recharger", alias= {"reload"}, description = "Recharge l'addon de ce laboratoire",admin=true)
|
||||||
|
public void recharger(CCommandeDiscord commande) {
|
||||||
|
|
||||||
|
ArgumentsComplexes cc = commande.getArguments();
|
||||||
|
|
||||||
|
String lab = cc.getArguments().getOrDefault("labo", commande.getLaboId());
|
||||||
|
|
||||||
|
if(cc.getNommeCount()<2) {
|
||||||
|
repondre(commande, "Il vous faut préciser l'addon que vous voulez charger !").complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String addonPkg = comprendreAddon(cc.getNomme(1));
|
||||||
|
|
||||||
|
|
||||||
|
Laboratoire l = Julia.theJulia().getLaboratoires().get(lab);
|
||||||
|
|
||||||
|
try {
|
||||||
|
l.rechargeAddon(addonPkg, null);
|
||||||
|
}catch (Exception e) {
|
||||||
|
repondre(commande, "Impossible de recharger l'addon spécifié ! Contactez un admin julia.").complete();
|
||||||
|
erreur("Tentative de rechargement depuis l'internaddon", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
repondre(commande, String.format("L'addon %s a été rechargé dans le laboratoire %s", addonPkg, lab)).complete();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Une commande qui lance une IllegalStateException à des fins de tests.
|
||||||
|
*/
|
||||||
|
//XXX: À supprimer ou cacher
|
||||||
|
@Commande(name="caca",description = "Déclanche une exception ... Faut bien tester, hein !",admin=true)
|
||||||
|
public void caca(CCommandeDiscord commande) {
|
||||||
throw new IllegalStateException("Nan mais tout va bien ... je fait ce qu'on m'a demandé ^^");
|
throw new IllegalStateException("Nan mais tout va bien ... je fait ce qu'on m'a demandé ^^");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringDistance addonMetric = StringDistances.levenshtein();
|
||||||
|
final float maxAcceptableDistance = 8.0f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie le pkg d'un addon disponible qui correspond le mieux au nom spécifié.
|
||||||
|
* @param nom Le nom, typiquement donné par l'utilisateur.
|
||||||
|
* @return Un pkg d'un internaddon, normalement chargeable.
|
||||||
|
*/
|
||||||
|
public String comprendreAddon(String nom) {
|
||||||
|
Set<String> pkgs = Julia.theJulia().pkgSet();
|
||||||
|
|
||||||
|
if(pkgs.contains(nom))
|
||||||
|
return nom; // C'est déjà un pkg donc bon
|
||||||
|
|
||||||
|
Optional<String> ops = pkgs.stream().filter(p -> p.endsWith("."+nom)).findAny();
|
||||||
|
if(ops.isPresent())
|
||||||
|
return ops.get();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
List<Pair<String, Float>> listProches = pkgs.stream()
|
||||||
|
.map(s -> Pair.of(s, addonMetric.distance(s.substring(s.lastIndexOf(".")+1), nom)))
|
||||||
|
.filter(e -> e.getRight() < maxAcceptableDistance)
|
||||||
|
.sorted((a,b) -> Float.compare(a.getRight(), b.getRight()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if(listProches.size()>1)
|
||||||
|
if(listProches.get(0).getRight() < listProches.get(1).getRight())
|
||||||
|
return listProches.get(0).getLeft();
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
else if(listProches.size()==1)
|
||||||
|
return listProches.get(0).getLeft();
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fait répondre à Julia sa réponse du message source
|
||||||
|
* @param commande La ccommande de requête
|
||||||
|
* @param message Le message à renvoyer
|
||||||
|
* @return L'action d'envoi de la réponse.
|
||||||
|
*/
|
||||||
|
public MessageAction repondre(CCommandeDiscord commande, MessageEmbed message) {
|
||||||
|
return commande.getMessage().replyEmbeds(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fait répondre à Julia sa réponse du message source
|
||||||
|
* @param commande La ccommande de requête
|
||||||
|
* @param message Le message à renvoyer
|
||||||
|
* @return L'action d'envoi de la réponse.
|
||||||
|
*/
|
||||||
|
public MessageAction repondre(CCommandeDiscord commande, Message message) {
|
||||||
|
return commande.getMessage().reply(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fait répondre à Julia sa réponse du message source
|
||||||
|
* @param commande La ccommande de requête
|
||||||
|
* @param message Le contenu du message à renvoyer
|
||||||
|
* @return L'action d'envoi de la réponse.
|
||||||
|
*/
|
||||||
|
public MessageAction repondre(CCommandeDiscord commande, String message) {
|
||||||
|
return commande.getMessage().reply(message).mentionRepliedUser(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class InternalddonCCommande implements DiscordCCommande,StringCCommande{
|
public String authorName(CCommandeDiscord commande) {
|
||||||
|
if(commande.getMessage().isFromGuild())
|
||||||
|
return ((GuildChannel)commande.getChannel()).getGuild().retrieveMember(commande.getUser()).complete().getEffectiveName();
|
||||||
|
else
|
||||||
|
return commande.getUser().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Une simple implémentation de {@link CCommandeDiscord} et de {@link CCommandeString} afin d'appeler
|
||||||
|
* les commandes depuis les events jda.
|
||||||
|
* @author mysaa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class InternalddonCCommande implements CCommandeDiscord,CCommandeString{
|
||||||
|
|
||||||
Message m;
|
Message m;
|
||||||
Laboratory labo;
|
Laboratoire labo;
|
||||||
|
|
||||||
public InternalddonCCommande(MessageReceivedEvent e,Laboratory labo) {
|
/**
|
||||||
|
* Crée une simple commande.
|
||||||
|
* @param e L'évenement trahissant la récéption de la commande.
|
||||||
|
* @param labo Le laboratoire associé à la commande.
|
||||||
|
*/
|
||||||
|
public InternalddonCCommande(MessageReceivedEvent e,Laboratoire labo) {
|
||||||
m = e.getMessage();
|
m = e.getMessage();
|
||||||
this.labo = labo;
|
this.labo = labo;
|
||||||
}
|
}
|
||||||
@ -214,7 +543,7 @@ public class Internaddon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandArguments getArguments() {
|
public ArgumentsComplexes getArguments() {
|
||||||
return parseCommandArguments(getStringCommand());
|
return parseCommandArguments(getStringCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,14 +578,20 @@ public class Internaddon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Laboratory getLabo() {
|
public String getLaboId() {
|
||||||
return labo;
|
return labo.getL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommandArguments parseCommandArguments(String raw) {
|
/**
|
||||||
|
* Comprend une ligne de commande, en séparant les nommes, flags et arguments en
|
||||||
|
* un seul objet.
|
||||||
|
* @param raw La ligne de commande à parser
|
||||||
|
* @return L'objet arguments complexes contenant toutes les données séparées.
|
||||||
|
*/
|
||||||
|
public static ArgumentsComplexes parseCommandArguments(String raw) {
|
||||||
|
|
||||||
List<String> nommes = new ArrayList<String>();
|
List<String> nommes = new ArrayList<String>();
|
||||||
Map<String,String> arguments = new HashMap<>();
|
Map<String,String> arguments = new HashMap<>();
|
||||||
@ -328,7 +663,7 @@ public class Internaddon {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CommandArguments(nommes, arguments, flags);
|
return new ArgumentsComplexes(nommes, arguments, flags);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
package com.bernard.juliabot.internaddon;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import net.dv8tion.jda.api.entities.Message;
|
|
||||||
|
|
||||||
public class UnstableMessage extends OutputStream{
|
|
||||||
|
|
||||||
MConsumer thisConsumer = new MConsumer();
|
|
||||||
|
|
||||||
public UnstableMessage(Message m) {
|
|
||||||
// TODO Auto-generated constructor stub
|
|
||||||
m.editMessage(""/* a préciser */).queue(thisConsumer, (e) -> {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(int arg0) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MConsumer implements Consumer<Message>{
|
|
||||||
@Override
|
|
||||||
public void accept(Message arg0) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user